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.
- checksums.yaml +4 -4
- data/.claude/commands/docs/write-comments.md +36 -0
- data/.github/CODEOWNERS +1 -1
- data/.github/workflows/ci.yaml +10 -6
- data/.gitignore +0 -1
- data/.rubocop.yml +7 -1
- data/.ruby-version +1 -1
- data/CLAUDE.md +2 -2
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +19 -18
- data/Gemfile.lock +35 -58
- data/README.md +118 -1432
- data/README_LEGACY.md +1464 -0
- data/Rakefile +39 -4
- data/dev.yml +29 -0
- data/dsl/agent_sessions.rb +20 -0
- data/dsl/async_cogs.rb +49 -0
- data/dsl/async_cogs_complex.rb +67 -0
- data/dsl/call.rb +44 -0
- data/dsl/collect_from.rb +72 -0
- data/dsl/json_output.rb +28 -0
- data/dsl/map.rb +55 -0
- data/dsl/map_reduce.rb +37 -0
- data/dsl/map_with_index.rb +49 -0
- data/dsl/next_break.rb +45 -0
- data/dsl/next_break_parallel.rb +44 -0
- data/dsl/outputs.rb +39 -0
- data/dsl/outputs_bang.rb +36 -0
- data/dsl/parallel_map.rb +37 -0
- data/dsl/prompts/simple_prompt.md.erb +3 -0
- data/dsl/prototype.rb +5 -7
- data/dsl/repeat_loop_results.rb +53 -0
- data/dsl/ruby_cog.rb +72 -0
- data/dsl/simple_agent.rb +18 -0
- data/dsl/simple_chat.rb +15 -1
- data/dsl/simple_repeat.rb +29 -0
- data/dsl/skip.rb +36 -0
- data/dsl/step_communication.rb +2 -3
- data/dsl/targets_and_params.rb +57 -0
- data/dsl/temperature.rb +17 -0
- data/dsl/temporary_directory.rb +22 -0
- data/dsl/tutorial/01_your_first_workflow/README.md +179 -0
- data/dsl/tutorial/01_your_first_workflow/configured_chat.rb +33 -0
- data/dsl/tutorial/01_your_first_workflow/hello.rb +23 -0
- data/dsl/tutorial/02_chaining_cogs/README.md +310 -0
- data/dsl/tutorial/02_chaining_cogs/code_review.rb +104 -0
- data/dsl/tutorial/02_chaining_cogs/session_resumption.rb +92 -0
- data/dsl/tutorial/02_chaining_cogs/simple_chain.rb +84 -0
- data/dsl/tutorial/03_targets_and_params/README.md +230 -0
- data/dsl/tutorial/03_targets_and_params/multiple_targets.rb +65 -0
- data/dsl/tutorial/03_targets_and_params/single_target.rb +65 -0
- data/dsl/tutorial/04_configuration_options/README.md +209 -0
- data/dsl/tutorial/04_configuration_options/control_display_and_temperature.rb +104 -0
- data/dsl/tutorial/04_configuration_options/simple_config.rb +68 -0
- data/dsl/tutorial/05_control_flow/README.md +156 -0
- data/dsl/tutorial/05_control_flow/conditional_execution.rb +62 -0
- data/dsl/tutorial/05_control_flow/handling_failures.rb +77 -0
- data/dsl/tutorial/06_reusable_scopes/README.md +172 -0
- data/dsl/tutorial/06_reusable_scopes/accessing_scope_outputs.rb +126 -0
- data/dsl/tutorial/06_reusable_scopes/basic_scope.rb +63 -0
- data/dsl/tutorial/06_reusable_scopes/parameterized_scope.rb +78 -0
- data/dsl/tutorial/07_processing_collections/README.md +152 -0
- data/dsl/tutorial/07_processing_collections/basic_map.rb +70 -0
- data/dsl/tutorial/07_processing_collections/parallel_map.rb +74 -0
- data/dsl/tutorial/08_iterative_workflows/README.md +231 -0
- data/dsl/tutorial/08_iterative_workflows/basic_repeat.rb +57 -0
- data/dsl/tutorial/08_iterative_workflows/conditional_break.rb +57 -0
- data/dsl/tutorial/09_async_cogs/README.md +197 -0
- data/dsl/tutorial/09_async_cogs/basic_async.rb +38 -0
- data/dsl/tutorial/README.md +222 -0
- data/dsl/working_directory.rb +16 -0
- data/exe/roast +1 -1
- data/internal/documentation/architectural-notes.md +115 -0
- data/internal/documentation/doc-comments-external.md +686 -0
- data/internal/documentation/doc-comments-internal.md +342 -0
- data/internal/documentation/doc-comments.md +211 -0
- data/lib/roast/dsl/cog/config.rb +274 -3
- data/lib/roast/dsl/cog/input.rb +53 -10
- data/lib/roast/dsl/cog/output.rb +297 -8
- data/lib/roast/dsl/cog/registry.rb +35 -3
- data/lib/roast/dsl/cog/stack.rb +1 -1
- data/lib/roast/dsl/cog/store.rb +5 -5
- data/lib/roast/dsl/cog.rb +70 -14
- data/lib/roast/dsl/cog_input_context.rb +36 -1
- data/lib/roast/dsl/cog_input_manager.rb +116 -7
- data/lib/roast/dsl/cogs/agent/config.rb +465 -0
- data/lib/roast/dsl/cogs/agent/input.rb +81 -0
- data/lib/roast/dsl/cogs/agent/output.rb +59 -0
- data/lib/roast/dsl/cogs/agent/provider.rb +51 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/claude_invocation.rb +185 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/message.rb +73 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/assistant_message.rb +36 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/result_message.rb +61 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/system_message.rb +47 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/text_message.rb +36 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_result_message.rb +47 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_use_message.rb +46 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/unknown_message.rb +27 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/user_message.rb +37 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/tool_result.rb +51 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/tool_use.rb +48 -0
- data/lib/roast/dsl/cogs/agent/providers/claude.rb +31 -0
- data/lib/roast/dsl/cogs/agent/stats.rb +92 -0
- data/lib/roast/dsl/cogs/agent/usage.rb +62 -0
- data/lib/roast/dsl/cogs/agent.rb +75 -0
- data/lib/roast/dsl/cogs/chat/config.rb +453 -0
- data/lib/roast/dsl/cogs/chat/input.rb +92 -0
- data/lib/roast/dsl/cogs/chat/output.rb +64 -0
- data/lib/roast/dsl/cogs/chat/session.rb +68 -0
- data/lib/roast/dsl/cogs/chat.rb +59 -56
- data/lib/roast/dsl/cogs/cmd.rb +251 -61
- data/lib/roast/dsl/cogs/ruby.rb +171 -0
- data/lib/roast/dsl/command_runner.rb +191 -0
- data/lib/roast/dsl/config_manager.rb +58 -11
- data/lib/roast/dsl/control_flow.rb +41 -0
- data/lib/roast/dsl/execution_manager.rb +162 -32
- data/lib/roast/dsl/nil_assertions.rb +23 -0
- data/lib/roast/dsl/system_cog/params.rb +32 -0
- data/lib/roast/dsl/system_cog.rb +36 -0
- data/lib/roast/dsl/system_cogs/call.rb +163 -0
- data/lib/roast/dsl/system_cogs/map.rb +454 -0
- data/lib/roast/dsl/system_cogs/repeat.rb +242 -0
- data/lib/roast/dsl/workflow.rb +26 -16
- data/lib/roast/dsl/workflow_context.rb +20 -0
- data/lib/roast/dsl/workflow_params.rb +24 -0
- data/lib/roast/helpers/minitest_coverage_runner.rb +1 -1
- data/lib/roast/sorbet_runtime_stub.rb +154 -0
- data/lib/roast/tools/apply_diff.rb +1 -3
- data/lib/roast/tools/cmd.rb +4 -3
- data/lib/roast/tools/read_file.rb +1 -1
- data/lib/roast/tools/update_files.rb +1 -1
- data/lib/roast/tools/write_file.rb +1 -1
- data/lib/roast/version.rb +1 -1
- data/lib/roast/workflow/base_workflow.rb +4 -0
- data/lib/roast/workflow/step_loader.rb +14 -2
- data/lib/roast-ai.rb +4 -0
- data/lib/roast.rb +58 -21
- data/{roast.gemspec → roast-ai.gemspec} +9 -13
- data/sorbet/rbi/gems/async@2.34.0.rbi +1577 -0
- data/sorbet/rbi/gems/cli-kit@5.2.0.rbi +2063 -0
- data/sorbet/rbi/gems/{cli-ui@2.3.0.rbi → cli-ui@2.7.0-6bdefd1d06305e5d6ae312ac76f9c88f88658dda.rbi} +1418 -1013
- data/sorbet/rbi/gems/console@1.34.2.rbi +1193 -0
- data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +50 -0
- data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +35 -0
- data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +41 -0
- data/sorbet/rbi/gems/io-event@1.14.0.rbi +724 -0
- data/sorbet/rbi/gems/metrics@0.15.0.rbi +9 -0
- data/sorbet/rbi/gems/traces@0.18.2.rbi +9 -0
- data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +1185 -5
- data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +311 -5
- data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +486 -5
- data/sorbet/tapioca/config.yml +6 -0
- data/sorbet/tapioca/require.rb +2 -0
- metadata +157 -30
- data/dsl/less_simple.rb +0 -112
- data/dsl/scoped_executors.rb +0 -28
- data/dsl/simple.rb +0 -8
- data/lib/roast/dsl/cogs/execute.rb +0 -46
- data/lib/roast/dsl/cogs/graph.rb +0 -53
- data/sorbet/rbi/gems/cgi@0.5.0.rbi +0 -2961
- data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +0 -568
- data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +0 -1991
- data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +0 -672
- data/sorbet/rbi/gems/dry-core@1.1.0.rbi +0 -1894
- data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +0 -659
- data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +0 -781
- data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +0 -1127
- data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +0 -3727
- data/sorbet/rbi/gems/dry-types@1.8.3.rbi +0 -3969
- data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +0 -1588
- data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +0 -136
- data/sorbet/rbi/gems/mime-types@3.7.0.rbi +0 -1342
- data/sorbet/rbi/gems/rack@2.2.19.rbi +0 -5676
- data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +0 -435
- data/sorbet/rbi/gems/yard@0.9.37.rbi +0 -18492
|
@@ -4,14 +4,495 @@
|
|
|
4
4
|
module Roast
|
|
5
5
|
module DSL
|
|
6
6
|
class ExecutionContext
|
|
7
|
-
#: (?Symbol?) {(Roast::DSL::Cogs::Cmd::Input) [self: Roast::DSL::CogInputContext] -> (String | Array[String] | nil)} -> void
|
|
8
|
-
def cmd(name = nil, &block); end
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
# Define the output of the current execution scope
|
|
9
|
+
#
|
|
10
|
+
# The `outputs!` block defines the 'primary' return value of this execution scope when it is invoked
|
|
11
|
+
# via the `call`, `map`, or `repeat` cogs. The block receives the current scope value and
|
|
12
|
+
# index as arguments, and executes in a `Roast::DSL::CogInputContext` where you can
|
|
13
|
+
# access any cog outputs from within the current scope.
|
|
14
|
+
#
|
|
15
|
+
# The `outputs!` block **always runs**, even if `break!` or `next!` are called within the
|
|
16
|
+
# scope. It is effectively a finalizer for the execution scope (though it will not run if
|
|
17
|
+
# the workflow aborts with an error).
|
|
18
|
+
#
|
|
19
|
+
# The alternative `outputs` block is identical to `outputs!`, but with relaxed handling of `CogOutputAccessError`s.
|
|
20
|
+
# `outputs!` will raise an exception if you attempt to access a cog that did not run (e.g., due to `skip!`)
|
|
21
|
+
# using its bang method for that cog -- i.e., the normal behaviour in a cog input block.
|
|
22
|
+
# `outputs`, on the other hand, will swallow these `CogOutputAccessError`s.
|
|
23
|
+
#
|
|
24
|
+
# It is recommended to use `outputs!` as the default unless you specifically need the relaxed error handling of
|
|
25
|
+
# `outputs`.
|
|
26
|
+
#
|
|
27
|
+
# The `outputs!` block **always runs**, even if `break!` or `next!` are called within the scope. It is
|
|
28
|
+
# effectively a finalizer for the execution scope (though it will not run if the workflow aborts with an error).
|
|
29
|
+
#
|
|
30
|
+
# NOTE: You can only have one output block in an execution scope: either `outputs!` or `outputs` depending
|
|
31
|
+
# on your requirements for that scope.
|
|
32
|
+
#
|
|
33
|
+
# ### Usage
|
|
34
|
+
# ```ruby
|
|
35
|
+
# execute(:refine_content) do
|
|
36
|
+
# chat(:improve) do |my, content, idx|
|
|
37
|
+
# my.prompt = "Improve this content (iteration #{idx}): #{content}"
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# ruby { |_, _, idx| break! if idx >= 3 }
|
|
41
|
+
#
|
|
42
|
+
# # This always runs, even when break! is called
|
|
43
|
+
# outputs! { chat!(:improve).response }
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# execute do
|
|
47
|
+
# repeat(:refine, run: :refine_content) { "Initial draft content" }
|
|
48
|
+
#
|
|
49
|
+
# ruby { puts "Final version: #{from(repeat!(:refine))}" }
|
|
50
|
+
# end
|
|
51
|
+
# ```
|
|
52
|
+
#
|
|
53
|
+
# ### See Also
|
|
54
|
+
# - `outputs` - Relaxed error handling (returns nil for cogs that didn't run)
|
|
55
|
+
# - `from` - Extract output from a `call` cog, or a single iteration of `map` or `repeat`
|
|
56
|
+
# - `collect` - Collect results from a `map` or `repeat` cog
|
|
57
|
+
# - `reduce` - Reduce results from a `map` or `repeat` cog
|
|
58
|
+
#
|
|
59
|
+
#: () {(untyped, Integer) [self: Roast::DSL::CogInputContext] -> untyped} -> void
|
|
60
|
+
def outputs!(&block); end
|
|
61
|
+
|
|
62
|
+
# Define the output of the current execution scope (relaxed error handling)
|
|
63
|
+
#
|
|
64
|
+
# NOTE: Unless you explicitly want the relaxed error handling, using `outputs!` is recommended.
|
|
65
|
+
#
|
|
66
|
+
# The `outputs` block defines the 'primary' return value of this execution scope when it is invoked
|
|
67
|
+
# via the `call`, `map`, or `repeat` cogs. The block receives the current scope value and
|
|
68
|
+
# index as arguments, and executes in a `Roast::DSL::CogInputContext` where you can
|
|
69
|
+
# access any cog outputs from within the current scope.
|
|
70
|
+
#
|
|
71
|
+
# The `outputs` block **always runs**, even if `break!` or `next!` are called within the
|
|
72
|
+
# scope. It is effectively a finalizer for the execution scope (though it will not run if
|
|
73
|
+
# the workflow aborts with an error).
|
|
74
|
+
#
|
|
75
|
+
# The `outputs` variant silently handles `CogOutputAccessError`s when accessing cogs that did not run
|
|
76
|
+
# (e.g., due to `skip!`), returning `nil` instead of raising an exception. This is a convenience
|
|
77
|
+
# formulation for use when you know your scope may abort early, and you only need to compute an
|
|
78
|
+
# `outputs` value when the scope runs fully. Use `outputs!` if you do want all such errors to be raised.
|
|
79
|
+
#
|
|
80
|
+
# NOTE: You can only have one output block in an execution scope: either `outputs!` or `outputs` depending
|
|
81
|
+
# on your requirements for that scope.
|
|
82
|
+
#
|
|
83
|
+
# ### Usage
|
|
84
|
+
# ```ruby
|
|
85
|
+
# execute(:analyze_text) do
|
|
86
|
+
# chat(:analysis) do |my, text|
|
|
87
|
+
# my.prompt = "Analyze this text and identify key themes: #{text}"
|
|
88
|
+
# end
|
|
89
|
+
#
|
|
90
|
+
# # Define what this scope returns
|
|
91
|
+
# outputs do |text|
|
|
92
|
+
# {
|
|
93
|
+
# original: text,
|
|
94
|
+
# analysis: chat!(:analysis).response,
|
|
95
|
+
# word_count: text.split.length
|
|
96
|
+
# }
|
|
97
|
+
# end
|
|
98
|
+
# end
|
|
99
|
+
#
|
|
100
|
+
# execute do
|
|
101
|
+
# call(:process, run: :analyze_text) { "The quick brown fox jumps over the lazy dog" }
|
|
102
|
+
#
|
|
103
|
+
# ruby { puts "Result: #{from(call!(:process))[:analysis]}" }
|
|
104
|
+
# end
|
|
105
|
+
# ```
|
|
106
|
+
#
|
|
107
|
+
# ### See Also
|
|
108
|
+
# - `outputs!` - Raises errors when accessing cogs that did not run
|
|
109
|
+
# - `from` - Extract output from a `call` cog, or a single iteration of `map` or `repeat`
|
|
110
|
+
# - `collect` - Collect results from a `map` or `repeat` cog
|
|
111
|
+
# - `reduce` - Reduce results from a `map` or `repeat` cog
|
|
112
|
+
#
|
|
113
|
+
#: () {(untyped, Integer) [self: Roast::DSL::CogInputContext] -> untyped} -> void
|
|
114
|
+
def outputs(&block); end
|
|
115
|
+
|
|
116
|
+
# Invoke a named execution scope with a provided value
|
|
117
|
+
#
|
|
118
|
+
# The `call` cog executes a named execution scope (defined with `execute(:name)`) with a
|
|
119
|
+
# provided value and optional index. The executed scope can access this value and index
|
|
120
|
+
# through cog input block parameters.
|
|
121
|
+
#
|
|
122
|
+
# The index parameter is primarily for compatibility, allowing a single execution scope to
|
|
123
|
+
# be invoked by both `call` (with a specific index) and `map` (with iteration indices).
|
|
124
|
+
#
|
|
125
|
+
# ### Usage
|
|
126
|
+
# ```ruby
|
|
127
|
+
# execute(:summarize_article) do
|
|
128
|
+
# chat(:summary) do |my, article_text|
|
|
129
|
+
# my.prompt = "Summarize this article in 2-3 sentences: #{article_text}"
|
|
130
|
+
# end
|
|
131
|
+
# end
|
|
132
|
+
#
|
|
133
|
+
# # The nameless execute scope is the workflow entry point
|
|
134
|
+
# execute do
|
|
135
|
+
# call(:process_article, run: :summarize_article) do |my|
|
|
136
|
+
# my.value = "Long article text goes here..."
|
|
137
|
+
# end
|
|
138
|
+
# end
|
|
139
|
+
# ```
|
|
140
|
+
#
|
|
141
|
+
# ### Input Options
|
|
142
|
+
#
|
|
143
|
+
# Set these attributes on the `my` input object within the block.
|
|
144
|
+
#
|
|
145
|
+
# - `value` (required) - The value to pass to the execution scope
|
|
146
|
+
# - `index` (optional) - The index value to pass to the scope (defaults to 0)
|
|
147
|
+
#
|
|
148
|
+
# You can also return a value from the block, which will be used as `my.value` if not set explicitly.
|
|
149
|
+
#
|
|
150
|
+
# ### See Also
|
|
151
|
+
# - `map` - Execute a scope for each item in a collection
|
|
152
|
+
# - `repeat` - Execute a scope multiple times in a loop
|
|
153
|
+
# - `from` - Extract the result from the called scope
|
|
154
|
+
#
|
|
155
|
+
#: (?Symbol?, run: Symbol) ?{(Roast::DSL::SystemCogs::Call::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> untyped} -> void
|
|
156
|
+
def call(name = nil, run:, &block); end
|
|
157
|
+
|
|
158
|
+
# Execute a scope for each item in a collection
|
|
159
|
+
#
|
|
160
|
+
# The `map` cog executes a named execution scope (defined with `execute(:name)`) for each
|
|
161
|
+
# item in a collection. Supports both serial and parallel execution modes. Each iteration
|
|
162
|
+
# receives the current item as its value and the iteration index.
|
|
163
|
+
#
|
|
164
|
+
# ### Usage
|
|
165
|
+
# ```ruby
|
|
166
|
+
# execute(:review_document) do
|
|
167
|
+
# chat(:review) do |my, document, idx|
|
|
168
|
+
# # The document from the collection is available as the second block parameter
|
|
169
|
+
# # The index in the collection is available as the third block parameter
|
|
170
|
+
# my.prompt = "Review document #{idx + 1}: #{document}. Provide feedback."
|
|
171
|
+
# end
|
|
172
|
+
# end
|
|
173
|
+
#
|
|
174
|
+
# execute do
|
|
175
|
+
# map(:review_all, run: :review_document) do |my|
|
|
176
|
+
# my.items = ["proposal.md", "design.md", "implementation.md"]
|
|
177
|
+
# end
|
|
178
|
+
# end
|
|
179
|
+
# ```
|
|
180
|
+
#
|
|
181
|
+
# ### Input Options
|
|
182
|
+
#
|
|
183
|
+
# Set these attributes on the `my` input object within the block:
|
|
184
|
+
#
|
|
185
|
+
# - `items` (required) - The collection of items to iterate over (any enumerable)
|
|
186
|
+
# - `initial_index` (optional) - The starting index for the first iteration (defaults to 0)
|
|
187
|
+
#
|
|
188
|
+
# You can also return a collection from the block, which will be used as `my.items` if not set explicitly.
|
|
189
|
+
#
|
|
190
|
+
# ### Flow Control
|
|
191
|
+
#
|
|
192
|
+
# Within the executed scope, call `break!` inside a cog's input block to terminate the map early.
|
|
193
|
+
# Any iterations not yet started will not run (their outputs will be `nil`) and any iterations in progress
|
|
194
|
+
# in parallel will be stopped (their outputs will also be `nil`)
|
|
195
|
+
# The `outputs` block will still run for the iteration in which `break!` is called.
|
|
196
|
+
#
|
|
197
|
+
# Within the executed scope, call `next!` inside a cog's input block to terminate the current iteration and begin
|
|
198
|
+
# next iteration immediately. The `outputs` block will still run for the current iteration, even when `next!` is called.
|
|
199
|
+
#
|
|
200
|
+
# ### Parallel Execution
|
|
201
|
+
#
|
|
202
|
+
# Configure parallel execution in the `config` block for this cog:
|
|
203
|
+
# - `parallel(n)` - Execute up to `n` iterations concurrently
|
|
204
|
+
# - `parallel!` - Execute all iterations concurrently with no limit
|
|
205
|
+
# - `no_parallel!` - Execute serially, one at a time (default)
|
|
206
|
+
#
|
|
207
|
+
# ### See Also
|
|
208
|
+
# - `call` - Execute a scope once with a single value
|
|
209
|
+
# - `repeat` - Execute a scope multiple times in a loop
|
|
210
|
+
# - `collect` - Collect all iteration results into an array
|
|
211
|
+
# - `reduce` - Reduce iteration results to a single value
|
|
212
|
+
#
|
|
213
|
+
#: (?Symbol?, run: Symbol) {(Roast::DSL::SystemCogs::Map::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> untyped} -> void
|
|
214
|
+
def map(name = nil, run:, &block); end
|
|
215
|
+
|
|
216
|
+
# Execute a scope multiple times in a loop
|
|
217
|
+
#
|
|
218
|
+
# The `repeat` cog executes a named execution scope (defined with `execute(:name)`) repeatedly
|
|
219
|
+
# until `break!` is called. The output from each iteration becomes the input value for the
|
|
220
|
+
# next iteration, allowing steps to be attempted repeatedly until a condition is met and for
|
|
221
|
+
# the loop body behavior to evolve from one iteration to the next.
|
|
222
|
+
#
|
|
223
|
+
# ### Usage
|
|
224
|
+
# ```ruby
|
|
225
|
+
# execute(:improve_until_acceptable) do
|
|
226
|
+
# chat(:improve) do |my, content, idx|
|
|
227
|
+
# my.prompt = "Improve this content (iteration #{idx}): #{content}"
|
|
228
|
+
# end
|
|
229
|
+
#
|
|
230
|
+
# chat(:evaluate) do |my|
|
|
231
|
+
# my.prompt = "Rate this content quality (1-10): #{chat!(:improve).response}"
|
|
232
|
+
# end
|
|
233
|
+
#
|
|
234
|
+
# # The loop will continue indefinitely until break! is called in a cog's input block.
|
|
235
|
+
# ruby { |_, _, idx| break! if chat!(:evaluate).text.to_i >= 8 || idx >= 5 }
|
|
236
|
+
#
|
|
237
|
+
# # The outputs block always runs, even on the iteration when break! is called.
|
|
238
|
+
# # The output of one iteration of the loop becomes the input to the next iteration.
|
|
239
|
+
# outputs! { chat!(:improve).response }
|
|
240
|
+
# end
|
|
241
|
+
#
|
|
242
|
+
# execute do
|
|
243
|
+
# repeat(:refine, run: :improve_until_acceptable) do |my|
|
|
244
|
+
# my.value = "Initial draft content"
|
|
245
|
+
# end
|
|
246
|
+
# end
|
|
247
|
+
# ```
|
|
248
|
+
#
|
|
249
|
+
# ### Input Options
|
|
250
|
+
#
|
|
251
|
+
# Set these attributes on the `my` input object within the block:
|
|
252
|
+
#
|
|
253
|
+
# - `value` (required) - The initial value to pass to the first iteration
|
|
254
|
+
# - `index` (optional) - The starting index for the first iteration (defaults to 0)
|
|
255
|
+
#
|
|
256
|
+
# You can also return a value from the block, which will be used as `my.value` if not set explicitly.
|
|
257
|
+
#
|
|
258
|
+
# ### Loop Control
|
|
259
|
+
#
|
|
260
|
+
# Within the executed scope, call `break!` inside a cog's input block to exit the loop. The
|
|
261
|
+
# final output of the `repeat` cog is the output of the iteration where `break!` is called.
|
|
262
|
+
# The `outputs` block always runs, even when `break!` is called (it acts as a finalizer).
|
|
263
|
+
#
|
|
264
|
+
# Within the executed scope, call `next!` inside a cog's input bloxk to exit the current iteration of the loop
|
|
265
|
+
# and begin the next iteration. The `outputs` block always run on each iteration, even when `next!` is called.
|
|
266
|
+
#
|
|
267
|
+
# ### See Also
|
|
268
|
+
# - `call` - Execute a scope once with a single value
|
|
269
|
+
# - `map` - Execute a scope for each item in a collection
|
|
270
|
+
# - `collect` - Access all iteration results (via `.results`)
|
|
271
|
+
# - `reduce` - Reduce iteration results to a single value (via `.results`)
|
|
272
|
+
#
|
|
273
|
+
#: (?Symbol?, run: Symbol) {(Roast::DSL::SystemCogs::Repeat::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> untyped} -> void
|
|
274
|
+
def repeat(name = nil, run:, &block); end
|
|
275
|
+
|
|
276
|
+
# Run a coding agent on the local machine
|
|
277
|
+
#
|
|
278
|
+
# The `agent` cog runs a coding agent on the local machine with access to local files,
|
|
279
|
+
# tools, and MCP servers. It is designed for coding tasks and any work requiring local
|
|
280
|
+
# filesystem access.
|
|
281
|
+
#
|
|
282
|
+
# The agent supports automatic session resumption across invocations.
|
|
283
|
+
#
|
|
284
|
+
# ### Usage
|
|
285
|
+
# ```ruby
|
|
286
|
+
# execute do
|
|
287
|
+
# agent(:code_analyzer) { "Analyze the code in src/ and suggest improvements" }
|
|
288
|
+
#
|
|
289
|
+
# # Resume from a previous session
|
|
290
|
+
# agent(:continue_analysis) do |my|
|
|
291
|
+
# my.prompt = "Now apply those improvements"
|
|
292
|
+
# my.session = agent!(:code_analyzer).session
|
|
293
|
+
# end
|
|
294
|
+
# end
|
|
295
|
+
# ```
|
|
296
|
+
#
|
|
297
|
+
# ### Input Options
|
|
298
|
+
#
|
|
299
|
+
# Set these attributes on the `my` input object within the block:
|
|
300
|
+
#
|
|
301
|
+
# - `prompt` (required) - The prompt to send to the agent
|
|
302
|
+
# - `session` (optional) - Session identifier for conversation continuity
|
|
303
|
+
#
|
|
304
|
+
# You can also return a String from the block, which will be used as `my.prompt` if not set explicitly.
|
|
305
|
+
#
|
|
306
|
+
# ### Output
|
|
307
|
+
#
|
|
308
|
+
# Access these attributes on the output object:
|
|
309
|
+
# - `response` - The agent's final text response
|
|
310
|
+
# - `session` - Session identifier for resuming the conversation
|
|
311
|
+
# - `stats` - Execution statistics (tokens, cost, etc.)
|
|
312
|
+
# - `text` - The response text with whitespace stripped (same as `.response.strip`)
|
|
313
|
+
# - `lines` - Array of lines from the response, each with whitespace stripped (same as `.response.lines.map(&:strip)`)
|
|
314
|
+
# - `json` - Parse the response as JSON, returning nil if parsing fails
|
|
315
|
+
# - `json!` - Parse the response as JSON, raising an error if parsing fails
|
|
316
|
+
#
|
|
317
|
+
# JSON parsing will aggressively and intelligently attempt to extract a JSON object from within surrounding
|
|
318
|
+
# text produced by the agent, so you should not need to worry if the agent's response looks like "Here is the
|
|
319
|
+
# JSON object you asked for: ..."
|
|
320
|
+
#
|
|
321
|
+
# ### See Also
|
|
322
|
+
# - `chat` - Pure LLM interaction without local system access
|
|
323
|
+
#
|
|
324
|
+
#: (?Symbol?) {(Roast::DSL::Cogs::Agent::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> (String | void)} -> void
|
|
325
|
+
def agent(name = nil, &block); end
|
|
326
|
+
|
|
327
|
+
# Perform pure LLM interaction
|
|
328
|
+
#
|
|
329
|
+
# The `chat` cog provides pure LLM interaction without local system access. While it
|
|
330
|
+
# cannot access local files or run local tools, it can still perform complex reasoning
|
|
331
|
+
# and access any provider-hosted tools and MCP servers according to the capabilities of the
|
|
332
|
+
# model and the facilities that it may be equipped with by the LLM provider.
|
|
333
|
+
#
|
|
334
|
+
# ### Usage
|
|
335
|
+
# ```ruby
|
|
336
|
+
# execute do
|
|
337
|
+
# chat(:analyzer) do |my|
|
|
338
|
+
# data = JSON.parse(File.read(target!))
|
|
339
|
+
# my.prompt = "Analyze this data and provide insights: #{data}"
|
|
340
|
+
# end
|
|
341
|
+
#
|
|
342
|
+
# chat(:summarizer) do |my|
|
|
343
|
+
# my.prompt = "Summarize this: #{chat!(:analyzer).response}"
|
|
344
|
+
# end
|
|
345
|
+
#
|
|
346
|
+
# # Resume a conversation by passing the session
|
|
347
|
+
# chat(:followup) do |my|
|
|
348
|
+
# my.prompt = "Can you elaborate on the second point?"
|
|
349
|
+
# my.session = chat!(:analyzer).session
|
|
350
|
+
# end
|
|
351
|
+
# end
|
|
352
|
+
# ```
|
|
353
|
+
#
|
|
354
|
+
# ### Input Options
|
|
355
|
+
#
|
|
356
|
+
# Set these attributes on the `my` input object within the block:
|
|
357
|
+
#
|
|
358
|
+
# - `prompt` (required) - The prompt to send to the language model
|
|
359
|
+
# - `session` (optional) - Session object for conversation continuity
|
|
360
|
+
#
|
|
361
|
+
# You can also return a String from the block, which will be used as `my.prompt` if not set explicitly.
|
|
362
|
+
#
|
|
363
|
+
# ### Output
|
|
364
|
+
#
|
|
365
|
+
# Access these attributes on the output object:
|
|
366
|
+
# - `response` - The LLM's text response
|
|
367
|
+
# - `session` - Session object for resuming the conversation
|
|
368
|
+
# - `text` - The response text with whitespace stripped (same as `.response.strip`)
|
|
369
|
+
# - `lines` - Array of lines from the response, each with whitespace stripped (same as `.response.lines.map(&:strip)`)
|
|
370
|
+
# - `json` - Parse the response as JSON, returning nil if parsing fails
|
|
371
|
+
# - `json!` - Parse the response as JSON, raising an error if parsing fails
|
|
372
|
+
#
|
|
373
|
+
# JSON parsing will aggressively and intelligently attempt to extract a JSON object from within surrounding
|
|
374
|
+
# text produced by the LLM, so you should not need to worry if the LLM's response looks like "Here is the
|
|
375
|
+
# JSON object you asked for: ..."
|
|
376
|
+
#
|
|
377
|
+
# ### See Also
|
|
378
|
+
# - `agent` - Run a coding agent with local filesystem access
|
|
379
|
+
#
|
|
380
|
+
#: (?Symbol?) {(Roast::DSL::Cogs::Chat::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> (String | void)} -> void
|
|
11
381
|
def chat(name = nil, &block); end
|
|
12
382
|
|
|
13
|
-
|
|
14
|
-
|
|
383
|
+
# Execute a shell command
|
|
384
|
+
#
|
|
385
|
+
# The `cmd` cog executes shell commands and captures their output and exit status. It can
|
|
386
|
+
# be configured to write its STDOUT and STDERR to the console as well.
|
|
387
|
+
#
|
|
388
|
+
# ### Usage
|
|
389
|
+
# ```ruby
|
|
390
|
+
# execute do
|
|
391
|
+
# cmd(:list_files) do |my|
|
|
392
|
+
# my.command = "ls"
|
|
393
|
+
# my.args = ["-la", "/tmp"]
|
|
394
|
+
# end
|
|
395
|
+
#
|
|
396
|
+
# # Simpler syntax: return command and args as array
|
|
397
|
+
# cmd(:git_status) { ["git", "status", "--short"] }
|
|
398
|
+
#
|
|
399
|
+
# # Return a command string (can include pipes and redirects)
|
|
400
|
+
# cmd(:process_data) { "cat data.txt | grep 'pattern' | wc -l" }
|
|
401
|
+
#
|
|
402
|
+
# # Complex shell command with pipe
|
|
403
|
+
# cmd(:find_errors) do
|
|
404
|
+
# "find . -name '*.log' | xargs grep 'ERROR' | head -n 10"
|
|
405
|
+
# end
|
|
406
|
+
# end
|
|
407
|
+
# ```
|
|
408
|
+
#
|
|
409
|
+
# ### Usage Style
|
|
410
|
+
#
|
|
411
|
+
# __Full command in a single string:__ Use this style when you want to take advantage of shell syntax like
|
|
412
|
+
# globbing, or use pipes, output redirection, etc.
|
|
413
|
+
#
|
|
414
|
+
# __Command and array of arguments:__ Use this style when you do not need shell features, and you specifically
|
|
415
|
+
# want to *avoid* having to escape values in command arguments.
|
|
416
|
+
#
|
|
417
|
+
# ### Input Options
|
|
418
|
+
#
|
|
419
|
+
# Set these attributes on the `my` input object within the block:
|
|
420
|
+
#
|
|
421
|
+
# - `command` (required) - The command to execute
|
|
422
|
+
# - `args` (optional) - Array of arguments to pass to the command
|
|
423
|
+
#
|
|
424
|
+
# You can also return from the block:
|
|
425
|
+
# - A String - used as the command (can include pipes, redirects, and other shell features)
|
|
426
|
+
# - An Array - first element is the command, remaining elements are args
|
|
427
|
+
#
|
|
428
|
+
# ### Output
|
|
429
|
+
#
|
|
430
|
+
# Access these attributes on the output object:
|
|
431
|
+
# - `out` - Standard output (STDOUT) from the command
|
|
432
|
+
# - `err` - Standard error (STDERR) from the command
|
|
433
|
+
# - `status` - The exit status of the command process
|
|
434
|
+
# - `text` - The STDOUT text with whitespace stripped (same as `.out.strip`)
|
|
435
|
+
# - `lines` - Array of lines from STDOUT, each with whitespace stripped (same as `.out.lines.map(&:strip)`)
|
|
436
|
+
# - `json` - Parse STDOUT as JSON, returning nil if parsing fails
|
|
437
|
+
# - `json!` - Parse STDOUT as JSON, raising an error if parsing fails
|
|
438
|
+
#
|
|
439
|
+
# ### See Also
|
|
440
|
+
# - `ruby` - Evaluate Ruby code within the workflow context
|
|
441
|
+
#
|
|
442
|
+
#: (?Symbol?) {(Roast::DSL::Cogs::Cmd::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> (String | Array[String] | void)} -> void
|
|
443
|
+
def cmd(name = nil, &block); end
|
|
444
|
+
|
|
445
|
+
# Evaluate Ruby code within the workflow context
|
|
446
|
+
#
|
|
447
|
+
# The `ruby` cog executes Ruby code in its input block. The return value of the block is
|
|
448
|
+
# passed through unchanged as the cog's output. This allows you to perform transformations,
|
|
449
|
+
# create data structures, or perform calculations that are easiest to accomplish with simple
|
|
450
|
+
# Ruby code.
|
|
451
|
+
#
|
|
452
|
+
# ### Usage
|
|
453
|
+
# ```ruby
|
|
454
|
+
# execute do
|
|
455
|
+
# ruby(:compute) { { sum: 1 + 2 + 3, product: 4 * 5 } }
|
|
456
|
+
#
|
|
457
|
+
# ruby(:transform) do
|
|
458
|
+
# data = ruby!(:compute).value
|
|
459
|
+
# "Sum: #{data[:sum]}, Product: #{data[:product]}"
|
|
460
|
+
# end
|
|
461
|
+
#
|
|
462
|
+
# # Access hash values directly on output via dynamic method dispatch
|
|
463
|
+
# ruby(:use_value) do |my|
|
|
464
|
+
# my.value = ruby!(:compute).sum # Accesses hash[:sum]
|
|
465
|
+
# end
|
|
466
|
+
#
|
|
467
|
+
# # Use for control flow
|
|
468
|
+
# ruby { |_, _, idx| break! if idx >= 3 }
|
|
469
|
+
# end
|
|
470
|
+
# ```
|
|
471
|
+
#
|
|
472
|
+
# ### Input Options
|
|
473
|
+
#
|
|
474
|
+
# Set these attributes on the `my` input object within the block:
|
|
475
|
+
#
|
|
476
|
+
# - `value` (required) - The value to pass through as output
|
|
477
|
+
#
|
|
478
|
+
# You can also return any Ruby object from the block, which will be used as `my.value` if
|
|
479
|
+
# not set explicitly.
|
|
480
|
+
#
|
|
481
|
+
# ### Output
|
|
482
|
+
#
|
|
483
|
+
# The output provides convenient dynamic method dispatch:
|
|
484
|
+
# - If the value responds to a method, it delegates to that method
|
|
485
|
+
# - If the value is a Hash, methods correspond to hash keys
|
|
486
|
+
# - Hash values that are Procs can be called directly as methods
|
|
487
|
+
# - Use `[]` for direct hash key access
|
|
488
|
+
# - Use `call()` to invoke Procs stored in the value
|
|
489
|
+
# - Use `.value` to access the raw output value
|
|
490
|
+
#
|
|
491
|
+
# ### See Also
|
|
492
|
+
# - `cmd` - Execute shell commands
|
|
493
|
+
#
|
|
494
|
+
#: (?Symbol?) {(Roast::DSL::Cogs::Ruby::Input, untyped, Integer) [self: Roast::DSL::CogInputContext] -> untyped} -> void
|
|
495
|
+
def ruby(name = nil, &block); end
|
|
15
496
|
end
|
|
16
497
|
end
|
|
17
498
|
end
|
data/sorbet/tapioca/config.yml
CHANGED
|
@@ -5,6 +5,12 @@ gem:
|
|
|
5
5
|
# - gem_name
|
|
6
6
|
# doc: true
|
|
7
7
|
# workers: 5
|
|
8
|
+
exclude:
|
|
9
|
+
# yard, via yard-sorbet, is required by tapioca itself, but unused in this project
|
|
10
|
+
# yard depends on rake, which seems not to be declared properly as a dependency of that gem
|
|
11
|
+
# since we don't use yard or rake ourselves, the easiest option is not to generate RBI files for these gems
|
|
12
|
+
- yard
|
|
13
|
+
- yard-sorbet
|
|
8
14
|
dsl:
|
|
9
15
|
# Add your `dsl` command parameters here:
|
|
10
16
|
#
|
data/sorbet/tapioca/require.rb
CHANGED
|
@@ -10,6 +10,8 @@ require "active_support/core_ext/string"
|
|
|
10
10
|
require "active_support/core_ext/string/inflections"
|
|
11
11
|
require "active_support/isolated_execution_state"
|
|
12
12
|
require "active_support/notifications"
|
|
13
|
+
require "async"
|
|
14
|
+
require "async/semaphore"
|
|
13
15
|
require "bundler/setup"
|
|
14
16
|
require "cli/kit"
|
|
15
17
|
require "cli/ui"
|