roast-ai 0.4.9 → 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.
Files changed (194) 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/CLAUDE.md +2 -2
  8. data/CONTRIBUTING.md +2 -0
  9. data/Gemfile +18 -18
  10. data/Gemfile.lock +46 -57
  11. data/README.md +118 -1432
  12. data/README_LEGACY.md +1464 -0
  13. data/Rakefile +39 -4
  14. data/dev.yml +29 -0
  15. data/dsl/agent_sessions.rb +20 -0
  16. data/dsl/async_cogs.rb +49 -0
  17. data/dsl/async_cogs_complex.rb +67 -0
  18. data/dsl/call.rb +44 -0
  19. data/dsl/collect_from.rb +72 -0
  20. data/dsl/demo/Gemfile +4 -0
  21. data/dsl/demo/Gemfile.lock +120 -0
  22. data/dsl/demo/cogs/local.rb +15 -0
  23. data/dsl/demo/simple_external_cog.rb +17 -0
  24. data/dsl/json_output.rb +28 -0
  25. data/dsl/map.rb +55 -0
  26. data/dsl/map_reduce.rb +37 -0
  27. data/dsl/map_with_index.rb +49 -0
  28. data/dsl/next_break.rb +40 -0
  29. data/dsl/next_break_parallel.rb +44 -0
  30. data/dsl/outputs.rb +39 -0
  31. data/dsl/outputs_bang.rb +36 -0
  32. data/dsl/parallel_map.rb +37 -0
  33. data/dsl/plugin-gem-example/.gitignore +8 -0
  34. data/dsl/plugin-gem-example/Gemfile +13 -0
  35. data/dsl/plugin-gem-example/Gemfile.lock +178 -0
  36. data/dsl/plugin-gem-example/lib/other.rb +17 -0
  37. data/dsl/plugin-gem-example/lib/plugin_gem_example.rb +5 -0
  38. data/dsl/plugin-gem-example/lib/simple.rb +15 -0
  39. data/dsl/plugin-gem-example/lib/version.rb +10 -0
  40. data/dsl/plugin-gem-example/plugin-gem-example.gemspec +28 -0
  41. data/dsl/prompts/simple_prompt.md.erb +3 -0
  42. data/dsl/prototype.rb +10 -4
  43. data/dsl/repeat_loop_results.rb +53 -0
  44. data/dsl/ruby_cog.rb +72 -0
  45. data/dsl/simple_agent.rb +18 -0
  46. data/dsl/simple_chat.rb +26 -0
  47. data/dsl/simple_repeat.rb +29 -0
  48. data/dsl/skip.rb +36 -0
  49. data/dsl/step_communication.rb +10 -5
  50. data/dsl/targets_and_params.rb +57 -0
  51. data/dsl/temperature.rb +17 -0
  52. data/dsl/temporary_directory.rb +22 -0
  53. data/dsl/tutorial/01_your_first_workflow/README.md +179 -0
  54. data/dsl/tutorial/01_your_first_workflow/configured_chat.rb +33 -0
  55. data/dsl/tutorial/01_your_first_workflow/hello.rb +23 -0
  56. data/dsl/tutorial/02_chaining_cogs/README.md +310 -0
  57. data/dsl/tutorial/02_chaining_cogs/code_review.rb +104 -0
  58. data/dsl/tutorial/02_chaining_cogs/session_resumption.rb +92 -0
  59. data/dsl/tutorial/02_chaining_cogs/simple_chain.rb +84 -0
  60. data/dsl/tutorial/03_targets_and_params/README.md +230 -0
  61. data/dsl/tutorial/03_targets_and_params/multiple_targets.rb +65 -0
  62. data/dsl/tutorial/03_targets_and_params/single_target.rb +65 -0
  63. data/dsl/tutorial/04_configuration_options/README.md +209 -0
  64. data/dsl/tutorial/04_configuration_options/control_display_and_temperature.rb +104 -0
  65. data/dsl/tutorial/04_configuration_options/simple_config.rb +68 -0
  66. data/dsl/tutorial/05_control_flow/README.md +156 -0
  67. data/dsl/tutorial/05_control_flow/conditional_execution.rb +62 -0
  68. data/dsl/tutorial/05_control_flow/handling_failures.rb +77 -0
  69. data/dsl/tutorial/06_reusable_scopes/README.md +172 -0
  70. data/dsl/tutorial/06_reusable_scopes/accessing_scope_outputs.rb +126 -0
  71. data/dsl/tutorial/06_reusable_scopes/basic_scope.rb +63 -0
  72. data/dsl/tutorial/06_reusable_scopes/parameterized_scope.rb +78 -0
  73. data/dsl/tutorial/07_processing_collections/README.md +152 -0
  74. data/dsl/tutorial/07_processing_collections/basic_map.rb +70 -0
  75. data/dsl/tutorial/07_processing_collections/parallel_map.rb +74 -0
  76. data/dsl/tutorial/08_iterative_workflows/README.md +231 -0
  77. data/dsl/tutorial/08_iterative_workflows/basic_repeat.rb +57 -0
  78. data/dsl/tutorial/08_iterative_workflows/conditional_break.rb +57 -0
  79. data/dsl/tutorial/09_async_cogs/README.md +197 -0
  80. data/dsl/tutorial/09_async_cogs/basic_async.rb +38 -0
  81. data/dsl/tutorial/README.md +222 -0
  82. data/dsl/working_directory.rb +16 -0
  83. data/exe/roast +1 -1
  84. data/internal/documentation/architectural-notes.md +115 -0
  85. data/internal/documentation/doc-comments-external.md +686 -0
  86. data/internal/documentation/doc-comments-internal.md +342 -0
  87. data/internal/documentation/doc-comments.md +211 -0
  88. data/lib/roast/dsl/cog/config.rb +280 -4
  89. data/lib/roast/dsl/cog/input.rb +73 -0
  90. data/lib/roast/dsl/cog/output.rb +313 -0
  91. data/lib/roast/dsl/cog/registry.rb +71 -0
  92. data/lib/roast/dsl/cog/stack.rb +3 -2
  93. data/lib/roast/dsl/cog/store.rb +11 -8
  94. data/lib/roast/dsl/cog.rb +108 -31
  95. data/lib/roast/dsl/cog_input_context.rb +44 -0
  96. data/lib/roast/dsl/cog_input_manager.rb +156 -0
  97. data/lib/roast/dsl/cogs/agent/config.rb +465 -0
  98. data/lib/roast/dsl/cogs/agent/input.rb +81 -0
  99. data/lib/roast/dsl/cogs/agent/output.rb +59 -0
  100. data/lib/roast/dsl/cogs/agent/provider.rb +51 -0
  101. data/lib/roast/dsl/cogs/agent/providers/claude/claude_invocation.rb +185 -0
  102. data/lib/roast/dsl/cogs/agent/providers/claude/message.rb +73 -0
  103. data/lib/roast/dsl/cogs/agent/providers/claude/messages/assistant_message.rb +36 -0
  104. data/lib/roast/dsl/cogs/agent/providers/claude/messages/result_message.rb +61 -0
  105. data/lib/roast/dsl/cogs/agent/providers/claude/messages/system_message.rb +47 -0
  106. data/lib/roast/dsl/cogs/agent/providers/claude/messages/text_message.rb +36 -0
  107. data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_result_message.rb +47 -0
  108. data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_use_message.rb +46 -0
  109. data/lib/roast/dsl/cogs/agent/providers/claude/messages/unknown_message.rb +27 -0
  110. data/lib/roast/dsl/cogs/agent/providers/claude/messages/user_message.rb +37 -0
  111. data/lib/roast/dsl/cogs/agent/providers/claude/tool_result.rb +51 -0
  112. data/lib/roast/dsl/cogs/agent/providers/claude/tool_use.rb +48 -0
  113. data/lib/roast/dsl/cogs/agent/providers/claude.rb +31 -0
  114. data/lib/roast/dsl/cogs/agent/stats.rb +92 -0
  115. data/lib/roast/dsl/cogs/agent/usage.rb +62 -0
  116. data/lib/roast/dsl/cogs/agent.rb +75 -0
  117. data/lib/roast/dsl/cogs/chat/config.rb +453 -0
  118. data/lib/roast/dsl/cogs/chat/input.rb +92 -0
  119. data/lib/roast/dsl/cogs/chat/output.rb +64 -0
  120. data/lib/roast/dsl/cogs/chat/session.rb +68 -0
  121. data/lib/roast/dsl/cogs/chat.rb +81 -0
  122. data/lib/roast/dsl/cogs/cmd.rb +291 -27
  123. data/lib/roast/dsl/cogs/ruby.rb +171 -0
  124. data/lib/roast/dsl/command_runner.rb +191 -0
  125. data/lib/roast/dsl/config_context.rb +2 -47
  126. data/lib/roast/dsl/config_manager.rb +143 -0
  127. data/lib/roast/dsl/control_flow.rb +41 -0
  128. data/lib/roast/dsl/execution_context.rb +9 -0
  129. data/lib/roast/dsl/execution_manager.rb +267 -0
  130. data/lib/roast/dsl/nil_assertions.rb +23 -0
  131. data/lib/roast/dsl/system_cog/params.rb +32 -0
  132. data/lib/roast/dsl/system_cog.rb +36 -0
  133. data/lib/roast/dsl/system_cogs/call.rb +162 -0
  134. data/lib/roast/dsl/system_cogs/map.rb +448 -0
  135. data/lib/roast/dsl/system_cogs/repeat.rb +242 -0
  136. data/lib/roast/dsl/workflow.rb +123 -0
  137. data/lib/roast/dsl/workflow_context.rb +20 -0
  138. data/lib/roast/dsl/workflow_params.rb +24 -0
  139. data/lib/roast/sorbet_runtime_stub.rb +154 -0
  140. data/lib/roast/tools/apply_diff.rb +1 -3
  141. data/lib/roast/tools/cmd.rb +4 -3
  142. data/lib/roast/tools/read_file.rb +1 -1
  143. data/lib/roast/tools/update_files.rb +1 -1
  144. data/lib/roast/tools/write_file.rb +1 -1
  145. data/lib/roast/version.rb +1 -1
  146. data/lib/roast/workflow/base_workflow.rb +4 -0
  147. data/lib/roast/workflow/step_loader.rb +14 -2
  148. data/lib/roast-ai.rb +4 -0
  149. data/lib/roast.rb +60 -22
  150. data/{roast.gemspec → roast-ai.gemspec} +10 -13
  151. data/sorbet/config +1 -0
  152. data/sorbet/rbi/gems/async@2.34.0.rbi +1577 -0
  153. data/sorbet/rbi/gems/cli-kit@5.2.0.rbi +2063 -0
  154. data/sorbet/rbi/gems/{cli-ui@2.3.0.rbi → cli-ui@2.7.0-6bdefd1d06305e5d6ae312ac76f9c88f88658dda.rbi} +1418 -1013
  155. data/sorbet/rbi/gems/console@1.34.2.rbi +1193 -0
  156. data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +50 -0
  157. data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +35 -0
  158. data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +41 -0
  159. data/sorbet/rbi/gems/io-event@1.14.0.rbi +724 -0
  160. data/sorbet/rbi/gems/marcel@1.1.0.rbi +239 -0
  161. data/sorbet/rbi/gems/metrics@0.15.0.rbi +9 -0
  162. data/sorbet/rbi/gems/ruby_llm@1.8.2.rbi +5703 -0
  163. data/sorbet/rbi/gems/traces@0.18.2.rbi +9 -0
  164. data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +1197 -0
  165. data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +314 -2
  166. data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +498 -0
  167. data/sorbet/tapioca/config.yml +6 -0
  168. data/sorbet/tapioca/require.rb +2 -0
  169. metadata +198 -34
  170. data/dsl/less_simple.rb +0 -112
  171. data/dsl/simple.rb +0 -8
  172. data/lib/roast/dsl/cog_execution_context.rb +0 -29
  173. data/lib/roast/dsl/cogs/graph.rb +0 -53
  174. data/lib/roast/dsl/cogs.rb +0 -65
  175. data/lib/roast/dsl/executor.rb +0 -82
  176. data/lib/roast/dsl/workflow_execution_context.rb +0 -47
  177. data/sorbet/rbi/gems/cgi@0.5.0.rbi +0 -2961
  178. data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +0 -568
  179. data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +0 -1991
  180. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +0 -672
  181. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +0 -1894
  182. data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +0 -659
  183. data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +0 -781
  184. data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +0 -1127
  185. data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +0 -3727
  186. data/sorbet/rbi/gems/dry-types@1.8.3.rbi +0 -3969
  187. data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +0 -1588
  188. data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +0 -136
  189. data/sorbet/rbi/gems/mime-types@3.7.0.rbi +0 -1342
  190. data/sorbet/rbi/gems/rack@2.2.18.rbi +0 -5659
  191. data/sorbet/rbi/gems/rbs-inline@0.12.0.rbi +0 -2170
  192. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +0 -435
  193. data/sorbet/rbi/gems/yard@0.9.37.rbi +0 -18492
  194. data/sorbet/rbi/shims/lib/roast/dsl/workflow_execution_context.rbi +0 -11
data/dsl/next_break.rb ADDED
@@ -0,0 +1,40 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ end
8
+
9
+ execute do
10
+ map(:loop, run: :loop_body) { 1..3 }
11
+
12
+ ruby do
13
+ results = collect(map!(:loop)) do
14
+ [ruby?(:one), ruby?(:two), ruby?(:three)]
15
+ end
16
+ results.each_with_index do |iteration_results, index|
17
+ puts "Iteration #{index}: #{iteration_results.presence || "did not run at all"}"
18
+ end
19
+ end
20
+ end
21
+
22
+ execute(:loop_body) do
23
+ ruby(:one) do |_, _, idx|
24
+ skip! if idx == 0
25
+ s = "[#{idx}] beginning"
26
+ puts s
27
+ s
28
+ end
29
+ ruby(:two) do |_, _, idx|
30
+ break! if idx == 1
31
+ s = "[#{idx}] middle"
32
+ puts s
33
+ s
34
+ end
35
+ ruby(:three) do |_, _, idx|
36
+ s = "[#{idx}] end"
37
+ puts s
38
+ s
39
+ end
40
+ end
@@ -0,0 +1,44 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ map { parallel! }
8
+ end
9
+
10
+ execute do
11
+ map(:loop, run: :loop_body) { 1..3 }
12
+
13
+ ruby do
14
+ results = collect(map!(:loop)) do
15
+ [ruby?(:one), ruby?(:two), ruby?(:three)]
16
+ end
17
+ results.each_with_index do |iteration_results, index|
18
+ puts "Iteration #{index}: #{iteration_results.presence || "did not run at all"}"
19
+ end
20
+ end
21
+ end
22
+
23
+ execute(:loop_body) do
24
+ ruby(:one) do |_, _, idx|
25
+ sleep(0.1) if idx == 0
26
+ sleep(0.2) if idx == 1
27
+ skip! if idx == 0
28
+ s = "[#{idx}] beginning"
29
+ puts s
30
+ s
31
+ end
32
+ ruby(:two) do |_, _, idx|
33
+ break! if idx == 1
34
+ s = "[#{idx}] middle"
35
+ puts s
36
+ s
37
+ end
38
+ ruby(:three) do |_, _, idx|
39
+ sleep(0.3) if idx == 2
40
+ s = "[#{idx}] end"
41
+ puts s
42
+ s
43
+ end
44
+ end
data/dsl/outputs.rb ADDED
@@ -0,0 +1,39 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ cmd { display! }
8
+ cmd(/to_/) { no_display! }
9
+ end
10
+
11
+ execute(:capitalize_a_word) do
12
+ cmd(:to_original) { |_, word| "echo \"#{word}\"" }
13
+ cmd(:to_upper) do |my, word|
14
+ my.command = "sh"
15
+ my.args << "-c"
16
+ my.args << "echo \"#{word}\" | tr '[:lower:]' '[:upper:]'"
17
+ end
18
+ cmd(:to_lower) do |my, word|
19
+ break! # the `outputs` will always be evaluated even if a cog breaks out of the execution scope
20
+ my.command = "sh"
21
+ my.args << "-c"
22
+ my.args << "echo \"#{word}\" | tr '[:upper:]' '[:lower:]'"
23
+ end
24
+ outputs do |word|
25
+ "Upper: #{cmd!(:to_upper).text} - Original: #{word}"
26
+ # `outputs` can return any kind of value
27
+ end
28
+ end
29
+
30
+ execute do
31
+ # Call a subroutine with `call` or `map`
32
+ call(:hello, run: :capitalize_a_word) { "Hello" }
33
+
34
+ cmd do
35
+ from_outputs = from(call!(:hello))
36
+ explicit_value_access = from(call!(:hello)) { cmd!(:to_upper).text }
37
+ "echo From Outputs: '\"#{from_outputs}\"\nExplicit Value Access: \"#{explicit_value_access}\"'"
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ cmd { display! }
8
+ cmd(/to_/) { no_display! }
9
+ end
10
+
11
+ execute(:subroutine1) do
12
+ ruby(:one) { "one" }
13
+ ruby(:two) { skip! }
14
+ # Attempting to access the output of a cog that did not run will not raise an exception inside the `outputs` block
15
+ # Instead, it will just return `nil`
16
+ outputs { ruby!(:two).value }
17
+ end
18
+
19
+ execute(:subroutine2) do
20
+ ruby(:one) { "one" }
21
+ ruby(:two) { skip! }
22
+ # Attempting to access the output of a cog that did not run *will* raise an exception inside the `outputs!` block
23
+ outputs! do
24
+ puts "❗️ This block is expected to raise an exception ❗️"
25
+ ruby!(:two).value
26
+ end
27
+ end
28
+
29
+ execute do
30
+ call(:one, run: :subroutine1) {}
31
+
32
+ ruby { puts "Using the `outputs` block should return `nil`: #{from(call!(:one)) || "nil"}" }
33
+
34
+ # The `outputs!` block in subroutine2 will raise an exception as soon as it is evaluated
35
+ call(:two, run: :subroutine2) {}
36
+ end
@@ -0,0 +1,37 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ cmd { display! }
8
+ map(:words) do
9
+ # By default, maximum parallelism is 1 and map executions will run synchronously
10
+ # Calling `parallel` with a larger value will allow multiple map items to be run in parallel, up to the limit given
11
+ # Calling `parallel!` or `parallel(0)` will allow unlimited parallelism, processing all map items in parallel
12
+ parallel 3
13
+ end
14
+ end
15
+
16
+ execute(:capitalize_a_word) do
17
+ cmd(:to_upper) do |_, word, index|
18
+ sleep(0.1) if index == 3 # "three" will be slow --> finishing second last
19
+ sleep(0.2) if index == 1 # "one" will be slowest --> finishing last
20
+ ["sh", "-c", "echo \"#{word}\" | tr '[:lower:]' '[:upper:]'"]
21
+ end
22
+ end
23
+
24
+ execute do
25
+ # Call a subroutine with `map`
26
+ map(:words, run: :capitalize_a_word) do |my|
27
+ my.items = ["one", "two", "three", "four", "five", "six"]
28
+ my.initial_index = 1 # for convenience, just because our items begin with "one"
29
+ end
30
+
31
+ cmd do |my|
32
+ my.command = "echo"
33
+ # Regardless of the order in which the items were processed by a parallel map,
34
+ # their results will always be provided to `collect` and `reduce` in the order in which they were given.
35
+ my.args << collect(map!(:words)) { cmd!(:to_upper).text }.join(", ")
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in plugin-gem-example.gemspec
6
+ gemspec
7
+
8
+ gem "irb"
9
+ gem "rake", "~> 13.0"
10
+
11
+ gem "minitest", "~> 5.16"
12
+
13
+ gem "rubocop", "~> 1.21"
@@ -0,0 +1,178 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ plugin-gem-example (0.1.0)
5
+ roast-ai
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (8.0.3)
11
+ base64
12
+ benchmark (>= 0.3)
13
+ bigdecimal
14
+ concurrent-ruby (~> 1.0, >= 1.3.1)
15
+ connection_pool (>= 2.2.5)
16
+ drb
17
+ i18n (>= 1.6, < 2)
18
+ logger (>= 1.4.2)
19
+ minitest (>= 5.1)
20
+ securerandom (>= 0.3)
21
+ tzinfo (~> 2.0, >= 2.0.5)
22
+ uri (>= 0.13.1)
23
+ addressable (2.8.7)
24
+ public_suffix (>= 2.0.2, < 7.0)
25
+ ast (2.4.3)
26
+ base64 (0.3.0)
27
+ benchmark (0.4.1)
28
+ bigdecimal (3.3.1)
29
+ cli-kit (5.0.1)
30
+ cli-ui (~> 2.0)
31
+ cli-ui (2.3.0)
32
+ concurrent-ruby (1.3.5)
33
+ connection_pool (2.5.4)
34
+ date (3.4.1)
35
+ diff-lcs (1.6.2)
36
+ dotenv (3.1.8)
37
+ drb (2.2.3)
38
+ erb (5.1.1)
39
+ event_stream_parser (1.0.0)
40
+ faraday (2.14.0)
41
+ faraday-net_http (>= 2.0, < 3.5)
42
+ json
43
+ logger
44
+ faraday-multipart (1.1.1)
45
+ multipart-post (~> 2.0)
46
+ faraday-net_http (3.4.1)
47
+ net-http (>= 0.5.0)
48
+ faraday-retry (2.3.2)
49
+ faraday (~> 2.0)
50
+ i18n (1.14.7)
51
+ concurrent-ruby (~> 1.0)
52
+ io-console (0.8.1)
53
+ irb (1.15.2)
54
+ pp (>= 0.6.0)
55
+ rdoc (>= 4.0.0)
56
+ reline (>= 0.4.2)
57
+ json (2.15.1)
58
+ json-schema (6.0.0)
59
+ addressable (~> 2.8)
60
+ bigdecimal (~> 3.1)
61
+ language_server-protocol (3.17.0.5)
62
+ lint_roller (1.1.0)
63
+ logger (1.7.0)
64
+ minitest (5.26.0)
65
+ multipart-post (2.4.1)
66
+ net-http (0.6.0)
67
+ uri
68
+ open_router (0.3.3)
69
+ activesupport (>= 6.0)
70
+ dotenv (>= 2)
71
+ faraday (>= 1)
72
+ faraday-multipart (>= 1)
73
+ ostruct (0.6.3)
74
+ parallel (1.27.0)
75
+ parser (3.3.9.0)
76
+ ast (~> 2.4.1)
77
+ racc
78
+ pp (0.6.3)
79
+ prettyprint
80
+ prettyprint (0.2.0)
81
+ prism (1.6.0)
82
+ psych (5.2.6)
83
+ date
84
+ stringio
85
+ public_suffix (6.0.2)
86
+ racc (1.8.1)
87
+ rainbow (3.1.1)
88
+ raix (1.0.3)
89
+ activesupport (>= 6.0)
90
+ faraday-retry (~> 2.0)
91
+ open_router (~> 0.2)
92
+ ostruct
93
+ ruby-openai (~> 8.1)
94
+ rake (13.3.0)
95
+ rdoc (6.15.0)
96
+ erb
97
+ psych (>= 4.0.0)
98
+ tsort
99
+ regexp_parser (2.11.3)
100
+ reline (0.6.2)
101
+ io-console (~> 0.5)
102
+ rexml (3.4.4)
103
+ roast-ai (0.4.9)
104
+ activesupport (>= 7.0)
105
+ cli-kit (~> 5.0)
106
+ cli-ui (= 2.3.0)
107
+ diff-lcs (~> 1.5)
108
+ json-schema
109
+ open_router (~> 0.3)
110
+ raix (~> 1.0.2)
111
+ ruby-graphviz (~> 1.2)
112
+ sqlite3 (~> 2.6)
113
+ thor (~> 1.3)
114
+ zeitwerk (~> 2.6)
115
+ rubocop (1.81.1)
116
+ json (~> 2.3)
117
+ language_server-protocol (~> 3.17.0.2)
118
+ lint_roller (~> 1.1.0)
119
+ parallel (~> 1.10)
120
+ parser (>= 3.3.0.2)
121
+ rainbow (>= 2.2.2, < 4.0)
122
+ regexp_parser (>= 2.9.3, < 3.0)
123
+ rubocop-ast (>= 1.47.1, < 2.0)
124
+ ruby-progressbar (~> 1.7)
125
+ unicode-display_width (>= 2.4.0, < 4.0)
126
+ rubocop-ast (1.47.1)
127
+ parser (>= 3.3.7.2)
128
+ prism (~> 1.4)
129
+ ruby-graphviz (1.2.5)
130
+ rexml
131
+ ruby-openai (8.3.0)
132
+ event_stream_parser (>= 0.3.0, < 2.0.0)
133
+ faraday (>= 1)
134
+ faraday-multipart (>= 1)
135
+ ruby-progressbar (1.13.0)
136
+ securerandom (0.4.1)
137
+ sqlite3 (2.7.4-aarch64-linux-gnu)
138
+ sqlite3 (2.7.4-aarch64-linux-musl)
139
+ sqlite3 (2.7.4-arm-linux-gnu)
140
+ sqlite3 (2.7.4-arm-linux-musl)
141
+ sqlite3 (2.7.4-arm64-darwin)
142
+ sqlite3 (2.7.4-x86-linux-gnu)
143
+ sqlite3 (2.7.4-x86-linux-musl)
144
+ sqlite3 (2.7.4-x86_64-darwin)
145
+ sqlite3 (2.7.4-x86_64-linux-gnu)
146
+ sqlite3 (2.7.4-x86_64-linux-musl)
147
+ stringio (3.1.7)
148
+ thor (1.4.0)
149
+ tsort (0.2.0)
150
+ tzinfo (2.0.6)
151
+ concurrent-ruby (~> 1.0)
152
+ unicode-display_width (3.2.0)
153
+ unicode-emoji (~> 4.1)
154
+ unicode-emoji (4.1.0)
155
+ uri (1.0.4)
156
+ zeitwerk (2.7.3)
157
+
158
+ PLATFORMS
159
+ aarch64-linux-gnu
160
+ aarch64-linux-musl
161
+ arm-linux-gnu
162
+ arm-linux-musl
163
+ arm64-darwin
164
+ x86-linux-gnu
165
+ x86-linux-musl
166
+ x86_64-darwin
167
+ x86_64-linux-gnu
168
+ x86_64-linux-musl
169
+
170
+ DEPENDENCIES
171
+ irb
172
+ minitest (~> 5.16)
173
+ plugin-gem-example!
174
+ rake (~> 13.0)
175
+ rubocop (~> 1.21)
176
+
177
+ BUNDLED WITH
178
+ 2.6.8
@@ -0,0 +1,17 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module MyCogNamespace
5
+ class Other < Roast::DSL::Cog
6
+ class Input < Roast::DSL::Cog::Input
7
+ def validate!
8
+ true
9
+ end
10
+ end
11
+
12
+ #: (Input) -> void
13
+ def execute(input)
14
+ puts "I'm a different cog!"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "simple"
5
+ require "other"
@@ -0,0 +1,15 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ class Simple < Roast::DSL::Cog
5
+ class Input < Roast::DSL::Cog::Input
6
+ def validate!
7
+ true
8
+ end
9
+ end
10
+
11
+ #: (Input) -> void
12
+ def execute(input)
13
+ puts "I'm a cog!"
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Plugin
5
+ module Gem
6
+ module Example
7
+ VERSION = "0.1.0"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "plugin-gem-example"
7
+ spec.version = Plugin::Gem::Example::VERSION
8
+ spec.authors = ["Sam Schmidt"]
9
+ spec.email = ["sam.schmidt@shopify.com"]
10
+
11
+ spec.summary = "TODO: Write a short summary, because RubyGems requires one."
12
+ spec.description = "TODO: Write a longer description or delete this line."
13
+ spec.homepage = "TODO: Put your gem's website or public repo URL here."
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.1.0"
16
+
17
+ spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
21
+ spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
+
23
+ # Uncomment to register a new dependency of your gem
24
+ spec.add_dependency("roast-ai")
25
+
26
+ # For more information and examples about making a new gem, check out our
27
+ # guide at: https://bundler.io/guides/creating_gem.html
28
+ end
@@ -0,0 +1,3 @@
1
+ You just told me the following about a lake. Make some stuff up about why that's nonsense.
2
+
3
+ <%= lake_answer %>
data/dsl/prototype.rb CHANGED
@@ -1,17 +1,23 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- #: self as Roast::DSL::Executor
4
+ #: self as Roast::DSL::Workflow
5
5
 
6
6
  config do
7
- cmd(:echo) { print_all! }
7
+ cmd(:echo) { display! }
8
+ cmd(/date/) { display! }
8
9
  end
9
10
 
10
11
  execute do
11
12
  # Anonymous cog. Added to the stack directly and given an autogenerated key in cog storage
12
13
  # Use for actions you do once and forget about, don't need configuration
13
- cmd { "touch tmp/#{SecureRandom.uuid} " }
14
+ cmd { |my| my.command = "touch tmp/#{SecureRandom.uuid}" }
14
15
 
15
16
  # Named cog. Configuration for this specific instance will be looked up from config block
16
- cmd(:echo) { "echo 'Hello World!'" }
17
+ cmd(:echo) { |my| my.command = "echo 'Hello World!'" }
18
+
19
+ # Cogs can implement input coercion for simple return values
20
+ fmt = "\"+%a %b %d %T %Z %Y\""
21
+ cmd(:date_today) { "/bin/date #{fmt}" }
22
+ cmd(:date_yesterday) { RUBY_PLATFORM.include?("darwin") ? "/bin/date -jv -1d #{fmt}" : "/bin/date -d '-1 day' #{fmt}" }
17
23
  end
@@ -0,0 +1,53 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ end
8
+
9
+ execute do
10
+ repeat(:loop, run: :loop_body) { 7 }
11
+
12
+ ruby do
13
+ # You can access the final output value of a `repeat` cog directly
14
+ result = repeat!(:loop)
15
+ puts "Ultimate Loop Result: #{result.value}"
16
+ end
17
+
18
+ ruby do
19
+ puts "---"
20
+ # You can also access the final result, or individual cog results, of any specific iteration
21
+ # In the same manner as you would use `from` to access the results of a single `call` invocation.
22
+ puts "First Iteration Result: #{from(repeat!(:loop).first)}"
23
+ puts "Final Iteration Result: #{from(repeat!(:loop).last)}"
24
+ puts "Second-to-last Iteration Result: #{from(repeat!(:loop).iteration(-2))}"
25
+ # NOTE: accessing a specific iteration will raise an IndexException if the requested index is out of bounds
26
+ # for the number of iterations that ran.
27
+ end
28
+
29
+ ruby do
30
+ puts "---"
31
+ # You can access the results of all iterations in the same manner as you would use `collect` or `reduce`
32
+ # to access the complete results of a `map` invocation.
33
+ puts "All :add cog outputs: #{collect(repeat!(:loop).results) { ruby!(:add).value }}"
34
+ puts "Sum of :add cog output: #{reduce(repeat!(:loop).results, 0) { |acc| acc + ruby!(:add).value }}"
35
+ end
36
+ end
37
+
38
+ execute(:loop_body) do
39
+ # on each loop iteration, the input value provided will be the output value of the previous iteration
40
+ # the initial value will be what was provided when `repeat` was called in the outer scope.
41
+ ruby(:add) do |_, num, idx|
42
+ new_num = num + idx
43
+ s = "iteration #{idx}: #{num} + #{idx} -> #{new_num}"
44
+ puts s
45
+ new_num
46
+ end
47
+
48
+ ruby { |_, _, idx| break! if idx >= 3 }
49
+
50
+ # The value provided to `outputs` will be the input value for the next iteration
51
+ # On the final iteration, it will also be the `repeat` cog's own output value
52
+ outputs { ruby!(:add).value }
53
+ end
data/dsl/ruby_cog.rb ADDED
@@ -0,0 +1,72 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ class MyClass
7
+ class << self
8
+ def add_stuff(a, b)
9
+ a + b
10
+ end
11
+ end
12
+ end
13
+
14
+ config do
15
+ cmd { display! }
16
+ end
17
+
18
+ execute do
19
+ cmd(:roast) { "echo Roast" }
20
+
21
+ # The `ruby` cog just passes the return value from its input block directly to its output.
22
+ # Letting you write whatever ruby code you want to generate that output
23
+ ruby(:whatever) do
24
+ # Do whatever you want in this block
25
+ value = cmd!(:roast).text
26
+ puts "Hello, #{value.upcase}"
27
+ puts "Calling a method: #{MyClass.add_stuff(3, 4)}"
28
+ # The value you return will be exposed as the .value attribute on the cog's output
29
+ 1..5
30
+ end
31
+
32
+ cmd(:numbers) do |my|
33
+ my.command = "echo"
34
+ value = ruby!(:whatever).value.map { |n| n.to_s * n }
35
+ my.args = value
36
+ end
37
+
38
+ ruby(:advanced_hash_output) do
39
+ {
40
+ some_number: 7,
41
+ some_string: "Hello, world!",
42
+ multiply: proc { |a, b| a * b },
43
+ }
44
+ end
45
+
46
+ ruby do
47
+ result = ruby!(:advanced_hash_output) #: untyped
48
+
49
+ # If the output's `value` is a Hash, you can access its items directly from the output object
50
+ puts "Some Number + 1: #{result[:some_number] + 1}"
51
+ # You can also access its items as getter methods on the output object
52
+ puts "Some String to Upper: #{result.some_string.upcase}"
53
+ # And, if one of those items is a proc, you can call it directly on the output object
54
+ puts "Multiply 4 * 3: #{result.multiply(4, 3)}"
55
+ end
56
+
57
+ ruby(:advanced_object_output) do |my|
58
+ my.value = <<~STRING
59
+ This is a long block of test
60
+ Consisting of many lines
61
+ Three, to be precise
62
+ STRING
63
+ end
64
+
65
+ ruby do
66
+ result = ruby!(:advanced_object_output) #: untyped
67
+
68
+ # You can also call methods on the output's `value` directly, regardless of its type
69
+ puts "The long string has #{result.lines.length} lines"
70
+ puts "And it has #{result.length} characters"
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ agent do
8
+ provider :claude
9
+ model "haiku"
10
+ initial_prompt "Always respond in haiku form"
11
+ show_prompt!
12
+ dump_raw_agent_messages_to "tmp/claude-messages.log"
13
+ end
14
+ end
15
+
16
+ execute do
17
+ agent { "What is the world's largest lake?" }
18
+ end
@@ -0,0 +1,26 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ chat(:lake) { model("gpt-4o") }
8
+ chat(:next) { model("gpt-4o-mini") }
9
+ end
10
+
11
+ execute do
12
+ # Ask a question
13
+ chat(:lake) { "What is the deepest lake?" }
14
+
15
+ # Continue the conversation (with a different model!)
16
+ chat(:next) do |my|
17
+ my.prompt = "What answer did you just give, and why?"
18
+ my.session = chat!(:lake).session
19
+ end
20
+
21
+ # Ask a question with a template prompt. You can pass variables to it as you would an ERB template
22
+ chat { template("dsl/prompts/simple_prompt.md.erb", { lake_answer: chat!(:lake).response }) }
23
+
24
+ # Shorthand to look up a template prompt
25
+ # chat { template("simple_prompt", { lake_answer: chat!(:lake).response }) }
26
+ end