roast-ai 0.4.10 → 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.
- 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/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 +40 -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 +248 -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 +162 -0
- data/lib/roast/dsl/system_cogs/map.rb +448 -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/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
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Chapter 3: Targets and Parameters
|
|
2
|
+
|
|
3
|
+
In the previous chapters, you learned how to create workflows and chain cogs together. Now you'll learn how to make your
|
|
4
|
+
workflows more flexible by accepting targets and custom parameters from the command line.
|
|
5
|
+
|
|
6
|
+
## What You'll Learn
|
|
7
|
+
|
|
8
|
+
- How to pass targets (files, URLs, etc.) to workflows
|
|
9
|
+
- How to use `target!` for single-target workflows
|
|
10
|
+
- How to access multiple targets with `targets`
|
|
11
|
+
- How to pass custom arguments with `args`
|
|
12
|
+
- How to pass key-value parameters with `kwargs`
|
|
13
|
+
- How to check for the presence of arguments and parameters
|
|
14
|
+
|
|
15
|
+
## Workflow Targets
|
|
16
|
+
|
|
17
|
+
Targets are inputs that you want your workflow to process—files, URLs, or any other data. They're specified on the
|
|
18
|
+
command line after your workflow file path:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bin/roast execute --executor=dsl workflow.rb https://example.com
|
|
22
|
+
bin/roast execute --executor=dsl workflow.rb README.md
|
|
23
|
+
bin/roast execute --executor=dsl workflow.rb src/*.rb
|
|
24
|
+
bin/roast execute --executor=dsl workflow.rb Gemfile Gemfile.lock
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Shell globs are expanded automatically, so `src/*.rb` will pass all Ruby files in the `src/` directory.
|
|
28
|
+
|
|
29
|
+
### Accessing a Single Target
|
|
30
|
+
|
|
31
|
+
Use `target!` when your workflow expects exactly one target:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
execute do
|
|
35
|
+
cmd(:fetch) do
|
|
36
|
+
"curl -sL #{target!}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
ruby do
|
|
40
|
+
puts "Target: #{target!}"
|
|
41
|
+
puts "Content length: #{cmd!(:fetch).out.length} bytes"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Run it with:
|
|
47
|
+
```bash
|
|
48
|
+
bin/roast execute --executor=dsl workflow.rb https://example.com
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Important:** `target!` raises an error if zero or multiple targets are provided. Use it when your workflow is
|
|
52
|
+
designed to process exactly one target.
|
|
53
|
+
|
|
54
|
+
### Accessing Multiple Targets
|
|
55
|
+
|
|
56
|
+
Use `targets` (plural) when your workflow can handle any number of files:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
execute do
|
|
60
|
+
ruby do
|
|
61
|
+
if targets.empty?
|
|
62
|
+
puts "No files provided"
|
|
63
|
+
else
|
|
64
|
+
puts "Processing #{targets.length} files:"
|
|
65
|
+
targets.each { |file| puts " - #{file}" }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The `targets` method always returns an array, which will be empty if the workflow is invoked with no targets specified.
|
|
72
|
+
|
|
73
|
+
## Custom Arguments
|
|
74
|
+
|
|
75
|
+
Custom arguments let you pass additional data to your workflows. They come after `--` on the command line:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
bin/roast execute --executor=dsl workflow.rb -- hello world
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Simple Arguments (args)
|
|
82
|
+
|
|
83
|
+
Simple word tokens become arguments, accessible as symbols:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
execute do
|
|
87
|
+
ruby do
|
|
88
|
+
puts "Arguments: #{args.inspect}" # [:hello, :world]
|
|
89
|
+
|
|
90
|
+
# Check if a specific argument is present
|
|
91
|
+
if arg?(:save_data)
|
|
92
|
+
puts "Will save incremental data files"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Run it with:
|
|
99
|
+
```bash
|
|
100
|
+
bin/roast execute --executor=dsl workflow.rb -- hello world
|
|
101
|
+
```
|
|
102
|
+
Or:
|
|
103
|
+
```bash
|
|
104
|
+
bin/roast execute --executor=dsl workflow.rb -- save_data something_else
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Key-Value Arguments (kwargs)
|
|
108
|
+
|
|
109
|
+
Use `key=value` format for key-value parameters:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
execute do
|
|
113
|
+
ruby do
|
|
114
|
+
# Check if a kwarg is present
|
|
115
|
+
if kwarg?(:format)
|
|
116
|
+
puts "Format: #{kwarg(:format)}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Access all kwargs
|
|
120
|
+
puts "All kwargs: #{kwargs.inspect}"
|
|
121
|
+
|
|
122
|
+
# Access a specific kwarg (returns nil if not present)
|
|
123
|
+
name = kwarg(:name)
|
|
124
|
+
puts "Name: #{name}"
|
|
125
|
+
|
|
126
|
+
# Access with error if missing
|
|
127
|
+
email = kwarg!(:email) # raises error if 'email' not provided
|
|
128
|
+
puts "Email: #{email}"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Run it with:
|
|
134
|
+
```bash
|
|
135
|
+
bin/roast execute --executor=dsl workflow.rb -- name=Alice format=json
|
|
136
|
+
```
|
|
137
|
+
Or:
|
|
138
|
+
```bash
|
|
139
|
+
bin/roast execute --executor=dsl workflow.rb -- name=Alice email=alice@example.net
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Notes:**
|
|
143
|
+
- Kwarg keys are parsed as symbols
|
|
144
|
+
- Kwarg values are always strings
|
|
145
|
+
- Simple words (without `=`) become args, not kwargs
|
|
146
|
+
|
|
147
|
+
## Combining Targets and Arguments
|
|
148
|
+
|
|
149
|
+
You can use targets and custom arguments together:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
bin/roast execute --executor=dsl workflow.rb file1.rb file2.rb -- save_data format=summary
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
In your workflow:
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
execute do
|
|
159
|
+
ruby do
|
|
160
|
+
puts "Processing #{targets.length} files"
|
|
161
|
+
puts "Save data: #{arg?(:save_data)}"
|
|
162
|
+
puts "Format: #{kwarg(:format) || "default"}"
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Accessing Parameters from Any Cog
|
|
168
|
+
|
|
169
|
+
All parameter accessors are available in any cog's input block:
|
|
170
|
+
|
|
171
|
+
```ruby
|
|
172
|
+
execute do
|
|
173
|
+
chat(:analyze) do
|
|
174
|
+
"Analyze this file: #{target!}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
agent(:process) do
|
|
178
|
+
files = targets.join("\n")
|
|
179
|
+
format = kwarg(:format) || "detailed"
|
|
180
|
+
"Process these files and provide a #{format} report:\n#{files}) "
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
cmd(:grep_pattern) do
|
|
184
|
+
pattern = kwarg!(:pattern) # Error if not provided
|
|
185
|
+
"grep '#{pattern}' #{targets.join(" ")}"
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Running the Workflows
|
|
191
|
+
|
|
192
|
+
To run the examples in this chapter:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Single target workflow (with a URL)
|
|
196
|
+
bin/roast execute --executor=dsl dsl/tutorial/03_targets_and_params/single_target.rb https://example.com
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Multiple targets with arguments
|
|
201
|
+
bin/roast execute --executor=dsl dsl/tutorial/03_targets_and_params/multiple_targets.rb \
|
|
202
|
+
Gemfile Gemfile.lock -- save_data format=summary
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Try It Yourself
|
|
206
|
+
|
|
207
|
+
1. **Single target processing** - Run the single_target workflow with different URLs
|
|
208
|
+
2. **Multiple files** - Use shell globs to pass multiple files at once
|
|
209
|
+
3. **Add arguments** - Try different combinations of args and kwargs
|
|
210
|
+
4. **Error handling** - See what happens when you use `target!` with multiple files
|
|
211
|
+
5. **Mix and match** - Combine targets with different argument combinations
|
|
212
|
+
|
|
213
|
+
## Key Takeaways
|
|
214
|
+
|
|
215
|
+
- Use `target!` when your workflow expects exactly one file/url/etc. (errors otherwise)
|
|
216
|
+
- Use `targets` to access an array of all targets (can be empty)
|
|
217
|
+
- Custom arguments come after `--` on the command line
|
|
218
|
+
- Simple words become `args` (as symbols)
|
|
219
|
+
- `key=value` pairs become `kwargs` (keys as symbols, values as strings)
|
|
220
|
+
- Use `arg?(:name)` to check if an argument is present
|
|
221
|
+
- Use `kwarg(:name)` to get a kwarg value (returns nil if missing)
|
|
222
|
+
- Use `kwarg!(:name)` to require a kwarg (errors if missing)
|
|
223
|
+
- All accessors work in any cog's input block
|
|
224
|
+
|
|
225
|
+
## What's Next?
|
|
226
|
+
|
|
227
|
+
In the next chapter, you'll learn about configuration options: how to fine-tune cog behavior, control what gets
|
|
228
|
+
displayed, and set up different models for different tasks.
|
|
229
|
+
|
|
230
|
+
But first, experiment with targets and parameters to see how they make your workflows more flexible and reusable!
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#: self as Roast::DSL::Workflow
|
|
5
|
+
|
|
6
|
+
# This workflow demonstrates processing multiple targets with custom arguments.
|
|
7
|
+
# It accepts any number of files and optional arguments for controlling output.
|
|
8
|
+
#
|
|
9
|
+
# Run it with:
|
|
10
|
+
# bin/roast execute --executor=dsl dsl/tutorial/03_targets_and_params/multiple_targets.rb \
|
|
11
|
+
# Gemfile Gemfile.lock
|
|
12
|
+
#
|
|
13
|
+
# Or try:
|
|
14
|
+
# bin/roast execute --executor=dsl dsl/tutorial/03_targets_and_params/multiple_targets.rb \
|
|
15
|
+
# dsl/**/*.rb -- count format=detailed
|
|
16
|
+
#
|
|
17
|
+
# Or get a little crazy:
|
|
18
|
+
# bin/roast execute --executor=dsl dsl/tutorial/03_targets_and_params/multiple_targets.rb \
|
|
19
|
+
# dsl/**/*.md -- format=json
|
|
20
|
+
|
|
21
|
+
config do
|
|
22
|
+
cmd { display! }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
execute do
|
|
26
|
+
# Show what we're processing
|
|
27
|
+
ruby do
|
|
28
|
+
puts "Processing #{targets.length} file(s):\n - #{targets.join("\n - ")}\n"
|
|
29
|
+
puts "Counting file lines" if arg?(:count)
|
|
30
|
+
puts "Arguments: #{args.inspect}" if args.any?
|
|
31
|
+
puts "Keyword arguments: #{kwargs.inspect}" if kwargs.any?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Analyze each file
|
|
35
|
+
chat(:analyze_files) do
|
|
36
|
+
format = kwarg(:format) || "summary"
|
|
37
|
+
<<~PROMPT
|
|
38
|
+
Please analyze these files and provide an #{format} overview:
|
|
39
|
+
|
|
40
|
+
#{targets.map { |f| "- #{f}" }.join("\n")}
|
|
41
|
+
|
|
42
|
+
Based on the filenames, what can you infer about this project?
|
|
43
|
+
What do you think these files are used for?
|
|
44
|
+
|
|
45
|
+
#{format == "detailed" ? "Provide detailed insights for each file." : "Keep it brief (2-3 sentences)."}
|
|
46
|
+
PROMPT
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Count total lines across all files
|
|
50
|
+
cmd(:total_lines) do |my|
|
|
51
|
+
my.stdin = targets.join("\n")
|
|
52
|
+
"xargs wc -l | awk '/total$/{print $1}'"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Display results
|
|
56
|
+
ruby do
|
|
57
|
+
puts "\n" + "=" * 60
|
|
58
|
+
puts "ANALYSIS RESULTS"
|
|
59
|
+
puts "=" * 60
|
|
60
|
+
puts "Total lines: #{arg?(:count) ? cmd!(:total_lines).out : "---"}"
|
|
61
|
+
puts "Format: #{kwarg(:format)}" if kwarg?(:format)
|
|
62
|
+
puts chat!(:analyze_files).text
|
|
63
|
+
puts "=" * 60
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#: self as Roast::DSL::Workflow
|
|
5
|
+
|
|
6
|
+
# This workflow demonstrates using target! to process a single URL.
|
|
7
|
+
# It expects exactly one URL to be provided on the command line.
|
|
8
|
+
#
|
|
9
|
+
# Run it with:
|
|
10
|
+
# bin/roast execute --executor=dsl dsl/tutorial/03_targets_and_params/single_target.rb \
|
|
11
|
+
# https://example.com
|
|
12
|
+
#
|
|
13
|
+
# Try running it with no URLs or multiple URLs to see how target! validates input.
|
|
14
|
+
|
|
15
|
+
config do
|
|
16
|
+
chat { no_show_response! }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
execute do
|
|
20
|
+
# Fetch the target URL
|
|
21
|
+
cmd(:fetch_url) do
|
|
22
|
+
"curl -sL #{target!}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Count words and lines in the content
|
|
26
|
+
cmd(:count_words) do
|
|
27
|
+
content = cmd!(:fetch_url).out
|
|
28
|
+
"echo #{content.shellescape} | wc -w"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
cmd(:count_lines) do |my|
|
|
32
|
+
content = cmd!(:fetch_url).out
|
|
33
|
+
my.stdin = content
|
|
34
|
+
"wc -l"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Analyze the content with an LLM
|
|
38
|
+
chat(:analyze) do
|
|
39
|
+
content = cmd!(:fetch_url).out
|
|
40
|
+
<<~PROMPT
|
|
41
|
+
Please analyze this web page content and provide a brief summary (2-3 sentences):
|
|
42
|
+
|
|
43
|
+
URL: #{target!}
|
|
44
|
+
|
|
45
|
+
Content:
|
|
46
|
+
#{content}
|
|
47
|
+
|
|
48
|
+
Focus on what the page contains and its purpose.
|
|
49
|
+
PROMPT
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Display the results
|
|
53
|
+
ruby do
|
|
54
|
+
puts "\n" + "=" * 60
|
|
55
|
+
puts "WEB PAGE ANALYSIS"
|
|
56
|
+
puts "=" * 60
|
|
57
|
+
puts "URL: #{target!}"
|
|
58
|
+
puts "Words: #{cmd!(:count_words).out.strip}"
|
|
59
|
+
puts "Lines: #{cmd!(:count_lines).out.strip}"
|
|
60
|
+
puts
|
|
61
|
+
puts "Summary:"
|
|
62
|
+
puts chat!(:analyze).response
|
|
63
|
+
puts "=" * 60
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Chapter 4: Configuration Options
|
|
2
|
+
|
|
3
|
+
In previous chapters, you learned the basics of creating workflows and chaining cogs together. Now you'll learn how to
|
|
4
|
+
configure cogs to control their behavior, use different models for different steps, and manage what gets displayed
|
|
5
|
+
during execution.
|
|
6
|
+
|
|
7
|
+
## What You'll Learn
|
|
8
|
+
|
|
9
|
+
- How to configure models and providers
|
|
10
|
+
- The difference between global and per-step configuration
|
|
11
|
+
- How to use different models for different steps
|
|
12
|
+
- How to control what gets displayed during execution
|
|
13
|
+
- Common model parameters like temperature
|
|
14
|
+
|
|
15
|
+
## Global Configuration
|
|
16
|
+
|
|
17
|
+
The `config` block at the top of your workflow sets defaults for all cogs of a given type:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
config do
|
|
21
|
+
chat do
|
|
22
|
+
model "gpt-4o-mini"
|
|
23
|
+
provider :openai
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
execute do
|
|
28
|
+
# All chat cogs will use gpt-4o-mini unless overridden
|
|
29
|
+
chat(:first) { "Analyze this data..." }
|
|
30
|
+
chat(:second) { "Summarize that analysis..." }
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Both chat cogs will use `gpt-4o-mini` from OpenAI because that's the global default you specified in the `config` block.
|
|
35
|
+
|
|
36
|
+
### Configuring Multiple Cog Types
|
|
37
|
+
|
|
38
|
+
You can set defaults for different cog types in the same config block:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
config do
|
|
42
|
+
chat do
|
|
43
|
+
model "gpt-4o-mini"
|
|
44
|
+
provider :openai
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
agent do
|
|
48
|
+
model "claude-3-5-haiku-20241022"
|
|
49
|
+
provider :claude
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Now all `chat` cogs use "gpt-4o-mini" and all `agent` cogs use Claude Code with the "haiku" model (unless you override
|
|
55
|
+
them individually).
|
|
56
|
+
|
|
57
|
+
## Per-Step Configuration
|
|
58
|
+
|
|
59
|
+
Override global configuration for specific named cogs by configuring them explicitly in the `config` block:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
config do
|
|
63
|
+
# Global default for all chat cogs
|
|
64
|
+
chat do
|
|
65
|
+
model "gpt-4o-mini"
|
|
66
|
+
provider :openai
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Override for a specific named cog
|
|
70
|
+
chat(:complex_task) do
|
|
71
|
+
model "gpt-5"
|
|
72
|
+
# any options you don't set here (we're not specifying 'provider' again, for instance) will be inherited from
|
|
73
|
+
# the global config, or will use Roast's default values.
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
execute do
|
|
78
|
+
# Uses global config (gpt-4o-mini)
|
|
79
|
+
chat(:simple_task) { "Categorize this: #{data}" }
|
|
80
|
+
|
|
81
|
+
# Uses the specific override (gpt-5)
|
|
82
|
+
chat(:complex_task) { "Perform deep analysis of this data: #{data}" }
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The `:simple_task` cog uses the configured global default, but `:complex_task` has its own configuration that overrides.
|
|
87
|
+
|
|
88
|
+
### Pattern-Based Configuration
|
|
89
|
+
|
|
90
|
+
You can also configure multiple cogs at once using a regex pattern:
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
config do
|
|
94
|
+
chat do
|
|
95
|
+
model "gpt-4o-mini"
|
|
96
|
+
provider :openai
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# All cogs with names matching this pattern use gpt-4o
|
|
100
|
+
chat(/analyze_/) do
|
|
101
|
+
model "gpt-4o"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
execute do
|
|
106
|
+
chat(:extract_data) { "..." } # Uses gpt-4o-mini
|
|
107
|
+
chat(:analyze_deep) { "..." } # Uses gpt-4o (matches pattern)
|
|
108
|
+
chat(:analyze_trends) { "..." } # Uses gpt-4o (matches pattern)
|
|
109
|
+
end
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This is useful when you have multiple similar cogs that need the same configuration.
|
|
113
|
+
|
|
114
|
+
## Display Options
|
|
115
|
+
|
|
116
|
+
Control what gets printed during workflow execution using display methods in your `config` block:
|
|
117
|
+
|
|
118
|
+
Different cogs have different display options. For the `chat` and `agent` cogs, you can control the display of
|
|
119
|
+
the prompt, response, usage statistics, and (for the agent cog) incremental progress messages.
|
|
120
|
+
|
|
121
|
+
- `show_prompt!` / `no_show_prompt!` - Control prompt display
|
|
122
|
+
- `show_response!` / `no_show_response!` - Control response display
|
|
123
|
+
- `show_stats!` / `no_show_stats!` - Control statistics display
|
|
124
|
+
|
|
125
|
+
For the `cmd` cog, you can control the display of standard output and standard error.
|
|
126
|
+
|
|
127
|
+
- `show_stdout!` / `no_show_stdout!` - Control stdout display
|
|
128
|
+
- `show_stderr!` / `no_show_stderr!` - Control stdout display
|
|
129
|
+
|
|
130
|
+
And for all cog types, you can quickly apply some typical configurations
|
|
131
|
+
|
|
132
|
+
- `display!` - Show everything (prompt, response, stats / standard output and error / etc.)
|
|
133
|
+
- `no_display!` / `quiet!` - Hide everything
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
config do
|
|
137
|
+
chat do
|
|
138
|
+
no_show_response! # Hide all responses by default
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
chat(:summarize) do
|
|
142
|
+
show_response! # But show the final summary
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This is useful for hiding intermediate steps while showing only the final output. See `control_display_and_temperature.rb` for more examples.
|
|
148
|
+
|
|
149
|
+
## Model Parameters
|
|
150
|
+
|
|
151
|
+
Fine-tune model behavior with additional parameters:
|
|
152
|
+
|
|
153
|
+
### Temperature
|
|
154
|
+
|
|
155
|
+
Controls randomness (0.0-1.0, where 0.0 = deterministic, 1.0 = more random):
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
config do
|
|
159
|
+
chat(:creative_writing) do
|
|
160
|
+
temperature(0.9)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
chat(:data_extraction) do
|
|
164
|
+
temperature(0.0)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
execute do
|
|
169
|
+
chat(:creative_writing) { "Write a creative story about: #{topic}" }
|
|
170
|
+
chat(:data_extraction) { "Extract structured data from: #{text}" }
|
|
171
|
+
end
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Running the Workflows
|
|
175
|
+
|
|
176
|
+
To run the examples in this chapter:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Simple configuration example
|
|
180
|
+
bin/roast execute --executor=dsl dsl/tutorial/04_configuration_options/simple_config.rb
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Configuring multiple parameters for multiple steps
|
|
185
|
+
bin/roast execute --executor=dsl dsl/tutorial/04_configuration_options/control_display_and_temperature.rb
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Try It Yourself
|
|
189
|
+
|
|
190
|
+
1. **Experiment with models** - Try different models for the same prompt and compare results
|
|
191
|
+
2. **Adjust temperature** - See how temperature affects creative vs factual outputs
|
|
192
|
+
3. **Control display** - Hide intermediate steps and only show final output
|
|
193
|
+
4. **Mix providers** - Use OpenAI for some steps and Anthropic for others
|
|
194
|
+
5. **Use patterns** - Try pattern-based configuration to configure multiple cogs at once
|
|
195
|
+
|
|
196
|
+
## Key Takeaways
|
|
197
|
+
|
|
198
|
+
- Use `config` blocks to set global defaults for cog types
|
|
199
|
+
- Override global config by naming specific cogs in the `config` block: `chat(:name) do ... end`
|
|
200
|
+
- Use pattern-based config with regex: `chat(/pattern/) do ... end`
|
|
201
|
+
- Use display methods like `show_prompt!` and `no_show_response!` to control what gets printed
|
|
202
|
+
- Different cog types can use different default configurations
|
|
203
|
+
|
|
204
|
+
## What's Next?
|
|
205
|
+
|
|
206
|
+
In the next chapter, you'll learn about control flow: how to conditionally skip steps, handle failures, and create
|
|
207
|
+
dynamic workflows that adapt based on intermediate results.
|
|
208
|
+
|
|
209
|
+
But first, experiment with different configurations to understand how they affect workflow behavior!
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#: self as Roast::DSL::Workflow
|
|
5
|
+
|
|
6
|
+
# This workflow demonstrates controlling what gets displayed during execution.
|
|
7
|
+
# Shows how to use show_prompt!, no_show_prompt!, show_response!, no_show_response!, and temperature.
|
|
8
|
+
|
|
9
|
+
config do
|
|
10
|
+
chat do
|
|
11
|
+
model "gpt-4o-mini"
|
|
12
|
+
show_prompt! # Show all prompts by default
|
|
13
|
+
no_show_response! # But hide responses by default
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Configure specific cogs with custom settings
|
|
17
|
+
chat(:generate_ideas) do
|
|
18
|
+
temperature(0.9) # Higher temperature for creative brainstorming
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
chat(:extract_names) do
|
|
22
|
+
temperature(0.0) # Low temperature for reliable extraction
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
chat(:evaluate_names) do
|
|
26
|
+
no_show_prompt! # Hide prompt for this step
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
chat(:pick_best) do
|
|
30
|
+
show_prompt! # Explicit show (redundant but clear)
|
|
31
|
+
show_response! # Show the final decision
|
|
32
|
+
temperature(0.3) # Low-medium for consistent evaluation
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
execute do
|
|
37
|
+
# Step 1: Generate creative content (high temperature configured above)
|
|
38
|
+
# The prompt is shown, response is hidden (our configured global default)
|
|
39
|
+
chat(:generate_ideas) do
|
|
40
|
+
<<~PROMPT
|
|
41
|
+
Brainstorm 5 creative names for a new project management tool focused on AI workflows.
|
|
42
|
+
|
|
43
|
+
Make them memorable, pronounceable, and available as .com domains (don't verify, just guess).
|
|
44
|
+
PROMPT
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Step 2: Extract structured data (low temperature configured above)
|
|
48
|
+
# The prompt is shown, response is hidden (our configured global default)
|
|
49
|
+
chat(:extract_names) do
|
|
50
|
+
ideas = chat!(:generate_ideas).response
|
|
51
|
+
<<~PROMPT
|
|
52
|
+
Extract just the names from this brainstorming output, format as JSON: `{ names: [...] }`
|
|
53
|
+
|
|
54
|
+
#{ideas}
|
|
55
|
+
PROMPT
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Step 3: Evaluate each name
|
|
59
|
+
# Prompt hidden (configured above), response hidden (global default)
|
|
60
|
+
chat(:evaluate_names) do
|
|
61
|
+
names = chat!(:extract_names).json![:names]
|
|
62
|
+
<<~PROMPT
|
|
63
|
+
Evaluate these product names for:
|
|
64
|
+
1. Memorability (1-10)
|
|
65
|
+
2. Professionalism (1-10)
|
|
66
|
+
3. Relevance to AI workflows (1-10)
|
|
67
|
+
|
|
68
|
+
Names:
|
|
69
|
+
- #{names.join("\n- ")}
|
|
70
|
+
PROMPT
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Step 4: Pick the best name
|
|
74
|
+
# Both prompt and response shown (configured above)
|
|
75
|
+
chat(:pick_best) do
|
|
76
|
+
<<~PROMPT
|
|
77
|
+
Based on these evaluations, pick the single best name and explain why in 2-3 sentences:
|
|
78
|
+
|
|
79
|
+
#{chat!(:evaluate_names).text}
|
|
80
|
+
PROMPT
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Summary of what was displayed:
|
|
84
|
+
ruby(:display_summary) do
|
|
85
|
+
puts "\n" + "=" * 70
|
|
86
|
+
puts "DISPLAY CONTROL DEMONSTRATION"
|
|
87
|
+
puts "=" * 70
|
|
88
|
+
puts <<~SUMMARY
|
|
89
|
+
|
|
90
|
+
What you saw:
|
|
91
|
+
- ✓ Prompts for steps 1-2 (global show_prompt!)
|
|
92
|
+
- ✗ Responses for steps 1-3 (global no_show_response!)
|
|
93
|
+
- ✗ Prompt for step 3 (configured with no_show_prompt!)
|
|
94
|
+
- ✓ Prompt and response for step 4 (configured with show_response!)
|
|
95
|
+
- ✓ LLM stats for every step (unconfigured; Roast default)
|
|
96
|
+
|
|
97
|
+
Temperature settings (all configured in config block):
|
|
98
|
+
- Step 1: 0.9 (higher, for creative brainstorming)
|
|
99
|
+
- Step 2: 0.0 (low, for reliable extraction)
|
|
100
|
+
- Step 4: 0.3 (low-medium, for consistent evaluation)
|
|
101
|
+
SUMMARY
|
|
102
|
+
puts "=" * 70 + "\n"
|
|
103
|
+
end
|
|
104
|
+
end
|