roast-ai 1.0.2 → 1.2.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 +1 -1
- data/.rubocop.yml +12 -1
- data/Gemfile +2 -2
- data/Gemfile.lock +149 -34
- data/README.md +56 -3
- data/examples/agent_with_multiple_prompts.rb +27 -0
- data/examples/custom_logging.rb +4 -2
- data/examples/demo/Gemfile.lock +49 -15
- data/examples/plugin-gem-example/Gemfile.lock +19 -15
- data/examples/simple_chat.rb +1 -1
- data/examples/simple_pi_agent.rb +18 -0
- data/internal/rubocop/cop/roast/no_test_class_nesting.rb +126 -0
- data/internal/rubocop/rubocop-roast.yml +6 -0
- data/internal/workflows/maintenance/branch_docs_impact.rb +97 -0
- data/internal/workflows/maintenance/deprecated_models_docs_updater.rb +78 -0
- data/lib/roast/cog/config.rb +1 -1
- data/lib/roast/cog/output.rb +2 -1
- data/lib/roast/cog/registry.rb +3 -3
- data/lib/roast/cog_input_manager.rb +28 -7
- data/lib/roast/cogs/agent/config.rb +2 -2
- data/lib/roast/cogs/agent/input.rb +20 -22
- data/lib/roast/cogs/agent/providers/claude/claude_invocation.rb +13 -5
- data/lib/roast/cogs/agent/providers/claude/messages/result_message.rb +1 -1
- data/lib/roast/cogs/agent/providers/claude/tool_result.rb +344 -4
- data/lib/roast/cogs/agent/providers/claude/tool_use.rb +356 -1
- data/lib/roast/cogs/agent/providers/claude.rb +16 -3
- data/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb +60 -0
- data/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb +57 -0
- data/lib/roast/cogs/agent/providers/pi/pi_invocation.rb +352 -0
- data/lib/roast/cogs/agent/providers/pi.rb +41 -0
- data/lib/roast/cogs/agent/stats.rb +29 -0
- data/lib/roast/cogs/agent/usage.rb +22 -0
- data/lib/roast/cogs/agent.rb +5 -6
- data/lib/roast/cogs/chat/config.rb +28 -2
- data/lib/roast/cogs/chat.rb +82 -10
- data/lib/roast/event.rb +1 -0
- data/lib/roast/event_monitor.rb +35 -3
- data/lib/roast/log.rb +21 -0
- data/lib/roast/log_formatter.rb +9 -7
- data/lib/roast/version.rb +1 -1
- data/lib/roast.rb +1 -3
- data/roast-ai.gemspec +2 -1
- data/sorbet/rbi/gems/activesupport@8.0.2.rbi +549 -383
- data/sorbet/rbi/gems/addressable@2.8.7.rbi +46 -44
- data/sorbet/rbi/gems/ast@2.4.3.rbi +7 -6
- data/sorbet/rbi/gems/async@2.34.0.rbi +21 -3
- data/sorbet/rbi/gems/benchmark@0.4.1.rbi +7 -7
- data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +198 -1
- data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +405 -328
- data/sorbet/rbi/gems/console@1.34.2.rbi +2 -2
- data/sorbet/rbi/gems/docile@1.4.1.rbi +30 -30
- data/sorbet/rbi/gems/drb@2.2.3.rbi +25 -25
- data/sorbet/rbi/gems/erubi@1.13.1.rbi +2 -0
- data/sorbet/rbi/gems/faraday-net_http@3.4.2.rbi +2 -77
- data/sorbet/rbi/gems/faraday-retry@2.3.2.rbi +2 -57
- data/sorbet/rbi/gems/faraday@2.14.1.rbi +382 -75
- data/sorbet/rbi/gems/guard-compat@1.2.1.rbi +1 -110
- data/sorbet/rbi/gems/guard-minitest@2.4.6.rbi +0 -139
- data/sorbet/rbi/gems/guard@2.19.1.rbi +38 -38
- data/sorbet/rbi/gems/hashdiff@1.2.0.rbi +3 -3
- data/sorbet/rbi/gems/i18n@1.14.7.rbi +53 -29
- data/sorbet/rbi/gems/io-event@1.14.0.rbi +67 -10
- data/sorbet/rbi/gems/json@2.18.1.rbi +227 -5
- data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +83 -0
- data/sorbet/rbi/gems/listen@3.9.0.rbi +7 -7
- data/sorbet/rbi/gems/logger@1.7.0.rbi +3 -3
- data/sorbet/rbi/gems/lumberjack@1.2.10.rbi +21 -21
- data/sorbet/rbi/gems/marcel@1.1.0.rbi +1 -1
- data/sorbet/rbi/gems/minitest-rg@5.3.0.rbi +0 -96
- data/sorbet/rbi/gems/minitest@5.25.5.rbi +1 -16
- data/sorbet/rbi/gems/net-http@0.9.1.rbi +27 -19
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +18 -0
- data/sorbet/rbi/gems/notiffany@0.1.3.rbi +20 -20
- data/sorbet/rbi/gems/ostruct@0.6.2.rbi +149 -15
- data/sorbet/rbi/gems/parser@3.3.8.0.rbi +141 -139
- data/sorbet/rbi/gems/prism@1.4.0.rbi +922 -864
- data/sorbet/rbi/gems/public_suffix@6.0.2.rbi +56 -35
- data/sorbet/rbi/gems/racc@1.8.1.rbi +10 -2
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +12 -12
- data/sorbet/rbi/gems/rake@13.3.0.rbi +219 -318
- data/sorbet/rbi/gems/{rbi@0.3.6.rbi → rbi@0.3.9.rbi} +612 -2267
- data/sorbet/rbi/gems/{rbs@3.9.4.rbi → rbs@4.0.0.dev.5.rbi} +2013 -680
- data/sorbet/rbi/gems/regexp_parser@2.10.0.rbi +151 -113
- data/sorbet/rbi/gems/require-hooks@0.2.3.rbi +110 -0
- data/sorbet/rbi/gems/rexml@3.4.2.rbi +24 -51
- data/sorbet/rbi/gems/rubocop-ast@1.45.1.rbi +506 -815
- data/sorbet/rbi/gems/rubocop-sorbet@0.10.5.rbi +16 -16
- data/sorbet/rbi/gems/rubocop@1.77.0.rbi +2692 -2327
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +8 -8
- data/sorbet/rbi/gems/ruby_llm@1.8.2.rbi +38 -23
- data/sorbet/rbi/gems/securerandom@0.4.1.rbi +1 -1
- data/sorbet/rbi/gems/simplecov-html@0.13.2.rbi +2 -131
- data/sorbet/rbi/gems/simplecov@0.22.0.rbi +28 -127
- data/sorbet/rbi/gems/{spoom@1.6.3.rbi → spoom@1.7.11.rbi} +1139 -2246
- data/sorbet/rbi/gems/sqlite3@2.9.0.rbi +91 -1
- data/sorbet/rbi/gems/{tapioca@0.16.11.rbi → tapioca@0.17.10.rbi} +721 -835
- data/sorbet/rbi/gems/thor@1.4.0.rbi +53 -53
- data/sorbet/rbi/gems/tsort@0.2.0.rbi +393 -0
- data/sorbet/rbi/gems/type_toolkit@0.0.5.rbi +49 -0
- data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +144 -143
- data/sorbet/rbi/gems/uri@1.1.1.rbi +7 -7
- data/sorbet/rbi/gems/vcr@6.3.1.rbi +53 -36
- data/sorbet/rbi/gems/webmock@3.25.1.rbi +38 -13
- data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +39 -272
- data/sorbet/rbi/shims/lib/roast/execution_context.rbi +3 -3
- data/tutorial/01_your_first_workflow/README.md +9 -5
- data/tutorial/01_your_first_workflow/configured_chat.rb +1 -1
- data/tutorial/02_chaining_cogs/README.md +2 -2
- data/tutorial/02_chaining_cogs/code_review.rb +1 -1
- data/tutorial/02_chaining_cogs/session_resumption.rb +1 -1
- data/tutorial/03_targets_and_params/README.md +1 -1
- data/tutorial/04_configuration_options/README.md +2 -2
- data/tutorial/08_iterative_workflows/README.md +1 -1
- data/tutorial/README.md +1 -1
- metadata +39 -17
- data/docs/AGENT_STEPS.md +0 -288
- data/docs/INSTRUMENTATION.md +0 -243
- data/docs/ITERATION_SYNTAX.md +0 -147
- data/docs/VALIDATION.md +0 -178
- data/lib/roast/nil_assertions.rb +0 -23
- /data/internal/documentation/{architectural-notes.md → comments/architectural-notes.md} +0 -0
- /data/internal/documentation/{doc-comments-external.md → comments/doc-comments-external.md} +0 -0
- /data/internal/documentation/{doc-comments-internal.md → comments/doc-comments-internal.md} +0 -0
- /data/internal/documentation/{doc-comments.md → comments/doc-comments.md} +0 -0
data/docs/INSTRUMENTATION.md
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
# Instrumentation Hooks in Roast
|
|
2
|
-
|
|
3
|
-
Roast provides built-in instrumentation hooks using ActiveSupport::Notifications, allowing you to track workflow execution, monitor performance, and integrate with your own monitoring systems.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The instrumentation system emits events at key points during workflow execution:
|
|
8
|
-
|
|
9
|
-
- Workflow lifecycle (start, complete)
|
|
10
|
-
- Step execution (start, complete, error)
|
|
11
|
-
- Chat completion/AI calls (start, complete, error)
|
|
12
|
-
- Tool function execution
|
|
13
|
-
|
|
14
|
-
## Configuration
|
|
15
|
-
|
|
16
|
-
To add custom instrumentation, create Ruby files in your project's `.roast/initializers/` directory. These files will be automatically loaded during workflow startup.
|
|
17
|
-
|
|
18
|
-
Example structure:
|
|
19
|
-
```
|
|
20
|
-
your-project/
|
|
21
|
-
├── .roast/
|
|
22
|
-
│ └── initializers/
|
|
23
|
-
│ ├── logging.rb
|
|
24
|
-
│ ├── metrics.rb
|
|
25
|
-
│ └── monitoring.rb
|
|
26
|
-
└── ...
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Available Events
|
|
30
|
-
|
|
31
|
-
### Workflow Events
|
|
32
|
-
|
|
33
|
-
- `roast.workflow.start` - Emitted when a workflow begins
|
|
34
|
-
- Payload: `{ workflow_path:, options:, name: }`
|
|
35
|
-
|
|
36
|
-
- `roast.workflow.complete` - Emitted when a workflow completes
|
|
37
|
-
- Payload: `{ workflow_path:, success:, execution_time: }`
|
|
38
|
-
|
|
39
|
-
### Step Events
|
|
40
|
-
|
|
41
|
-
- `roast.step.start` - Emitted when a step begins execution
|
|
42
|
-
- Payload: `{ step_name:, resource_type:, workflow_name: }`
|
|
43
|
-
|
|
44
|
-
- `roast.step.complete` - Emitted when a step completes successfully
|
|
45
|
-
- Payload: `{ step_name:, resource_type:, workflow_name:, success: true, execution_time:, result_size: }`
|
|
46
|
-
|
|
47
|
-
- `roast.step.error` - Emitted when a step encounters an error
|
|
48
|
-
- Payload: `{ step_name:, resource_type:, workflow_name:, error:, message:, execution_time: }`
|
|
49
|
-
|
|
50
|
-
### AI/Chat Completion Events
|
|
51
|
-
|
|
52
|
-
- `roast.chat_completion.start` - Emitted before an AI API call
|
|
53
|
-
- Payload: `{ model:, parameters: }`
|
|
54
|
-
|
|
55
|
-
- `roast.chat_completion.complete` - Emitted after successful AI API call
|
|
56
|
-
- Payload: `{ success: true, model:, parameters:, execution_time:, response_size: }`
|
|
57
|
-
|
|
58
|
-
- `roast.chat_completion.error` - Emitted when AI API call fails
|
|
59
|
-
- Payload: `{ error:, message:, model:, parameters:, execution_time: }`
|
|
60
|
-
|
|
61
|
-
### Tool Execution Events
|
|
62
|
-
|
|
63
|
-
- `roast.tool.execute` - Emitted when a tool function is called
|
|
64
|
-
- Payload: `{ function_name:, params: }`
|
|
65
|
-
|
|
66
|
-
- `roast.tool.complete` - Emitted when a tool function completes
|
|
67
|
-
- Payload: `{ function_name:, execution_time:, cache_enabled: }`
|
|
68
|
-
|
|
69
|
-
- `roast.tool.error` - Emitted when a tool execution fails
|
|
70
|
-
- Payload: `{ function_name:, error:, message:, execution_time: }`
|
|
71
|
-
|
|
72
|
-
## Example Usage
|
|
73
|
-
|
|
74
|
-
### Basic Logging
|
|
75
|
-
|
|
76
|
-
```ruby
|
|
77
|
-
# .roast/initializers/logging.rb
|
|
78
|
-
ActiveSupport::Notifications.subscribe(/roast\./) do |name, start, finish, id, payload|
|
|
79
|
-
duration = finish - start
|
|
80
|
-
puts "[#{name}] completed in #{duration.round(3)}s"
|
|
81
|
-
end
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Performance Monitoring
|
|
85
|
-
|
|
86
|
-
```ruby
|
|
87
|
-
# .roast/initializers/performance.rb
|
|
88
|
-
ActiveSupport::Notifications.subscribe("roast.step.complete") do |name, start, finish, id, payload|
|
|
89
|
-
duration = finish - start
|
|
90
|
-
if duration > 10.0
|
|
91
|
-
puts "WARNING: Step '#{payload[:step_name]}' took #{duration.round(1)}s"
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Integration with External Services
|
|
97
|
-
|
|
98
|
-
```ruby
|
|
99
|
-
# .roast/initializers/metrics.rb
|
|
100
|
-
ActiveSupport::Notifications.subscribe("roast.workflow.complete") do |name, start, finish, id, payload|
|
|
101
|
-
duration = finish - start
|
|
102
|
-
|
|
103
|
-
# Send to your metrics service
|
|
104
|
-
MyMetricsService.track_event("workflow_execution", {
|
|
105
|
-
workflow_path: payload[:workflow_path],
|
|
106
|
-
duration: duration,
|
|
107
|
-
success: payload[:success]
|
|
108
|
-
})
|
|
109
|
-
end
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Internal Shopify Example
|
|
113
|
-
|
|
114
|
-
For the internal Shopify version, you can use these instrumentation hooks to track metrics with Monorail:
|
|
115
|
-
|
|
116
|
-
```ruby
|
|
117
|
-
# .roast/initializers/monorail.rb
|
|
118
|
-
|
|
119
|
-
# Track workflow execution
|
|
120
|
-
ActiveSupport::Notifications.subscribe("roast.workflow.start") do |name, start, finish, id, payload|
|
|
121
|
-
Roast::Support::Monorail.track_command("run", {
|
|
122
|
-
"workflow_path" => payload[:workflow_path],
|
|
123
|
-
"options" => payload[:options],
|
|
124
|
-
"name" => payload[:name]
|
|
125
|
-
})
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
ActiveSupport::Notifications.subscribe("roast.workflow.complete") do |name, start, finish, id, payload|
|
|
129
|
-
Roast::Support::Monorail.track_command("run_complete", {
|
|
130
|
-
"workflow_path" => payload[:workflow_path],
|
|
131
|
-
"success" => payload[:success],
|
|
132
|
-
"execution_time" => payload[:execution_time]
|
|
133
|
-
})
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Track AI model usage and performance
|
|
137
|
-
ActiveSupport::Notifications.subscribe("roast.chat_completion.complete") do |name, start, finish, id, payload|
|
|
138
|
-
Roast::Support::Monorail.track_command("ai_usage", {
|
|
139
|
-
"model" => payload[:model],
|
|
140
|
-
"execution_time" => payload[:execution_time],
|
|
141
|
-
"response_size" => payload[:response_size],
|
|
142
|
-
"has_json" => payload[:parameters][:json] || false,
|
|
143
|
-
"has_loop" => payload[:parameters][:loop] || false
|
|
144
|
-
})
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# Track tool execution and caching
|
|
148
|
-
ActiveSupport::Notifications.subscribe("roast.tool.complete") do |name, start, finish, id, payload|
|
|
149
|
-
Roast::Support::Monorail.track_command("tool_usage", {
|
|
150
|
-
"function_name" => payload[:function_name],
|
|
151
|
-
"execution_time" => payload[:execution_time],
|
|
152
|
-
"cache_enabled" => payload[:cache_enabled]
|
|
153
|
-
})
|
|
154
|
-
end
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
See `examples/monorail_initializer.rb` for a complete example of Monorail integration.
|
|
158
|
-
|
|
159
|
-
## Best Practices
|
|
160
|
-
|
|
161
|
-
1. **Keep initializers focused**: Each initializer should handle a specific concern (logging, metrics, error reporting, etc.)
|
|
162
|
-
|
|
163
|
-
2. **Handle errors gracefully**: Wrap your subscriber code in error handling to prevent crashes:
|
|
164
|
-
```ruby
|
|
165
|
-
ActiveSupport::Notifications.subscribe("roast.workflow.start") do |name, start, finish, id, payload|
|
|
166
|
-
begin
|
|
167
|
-
# Your instrumentation code here
|
|
168
|
-
rescue => e
|
|
169
|
-
$stderr.puts "Instrumentation error: #{e.message}"
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
3. **Avoid blocking operations**: Instrumentation should be fast and non-blocking. For heavy operations, consider using async processing.
|
|
175
|
-
|
|
176
|
-
4. **Use pattern matching**: Subscribe to specific event patterns to reduce overhead:
|
|
177
|
-
```ruby
|
|
178
|
-
# Subscribe only to workflow events
|
|
179
|
-
ActiveSupport::Notifications.subscribe(/roast\.workflow\./) do |name, start, finish, id, payload|
|
|
180
|
-
# Handle only workflow events
|
|
181
|
-
end
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
5. **Consider performance impact**: While instrumentation is valuable, too many subscribers can impact performance. Be selective about what you instrument.
|
|
185
|
-
|
|
186
|
-
## Testing Your Instrumentation
|
|
187
|
-
|
|
188
|
-
You can test your instrumentation by creating a simple workflow and observing the events:
|
|
189
|
-
|
|
190
|
-
```yaml
|
|
191
|
-
# test_instrumentation.yml
|
|
192
|
-
name: instrumentation_test
|
|
193
|
-
steps:
|
|
194
|
-
- test_step
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
Then run:
|
|
198
|
-
```bash
|
|
199
|
-
roast execute test_instrumentation.yml some_file.rb
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
Your instrumentation should capture the workflow start, step execution, and workflow completion events.
|
|
203
|
-
|
|
204
|
-
## Available Tools
|
|
205
|
-
|
|
206
|
-
Roast provides several built-in tools that you can use in your workflows:
|
|
207
|
-
|
|
208
|
-
### WriteFile Tool
|
|
209
|
-
|
|
210
|
-
Writes content to a file, creating the file if it doesn't exist or overwriting it if it does.
|
|
211
|
-
|
|
212
|
-
```ruby
|
|
213
|
-
# Example usage in a prompt
|
|
214
|
-
write_file(path: "output.txt", content: "This is the file content")
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### UpdateFiles Tool
|
|
218
|
-
|
|
219
|
-
Applies a unified diff/patch to one or more files. Changes are applied atomically when possible.
|
|
220
|
-
|
|
221
|
-
```ruby
|
|
222
|
-
# Example usage in a prompt
|
|
223
|
-
update_files(diff: <<~DIFF, base_path: "/path/to/project", create_files: true)
|
|
224
|
-
--- a/file1.txt
|
|
225
|
-
+++ b/file1.txt
|
|
226
|
-
@@ -1,3 +1,4 @@
|
|
227
|
-
line1
|
|
228
|
-
+new line
|
|
229
|
-
line2
|
|
230
|
-
line3
|
|
231
|
-
|
|
232
|
-
--- a/file2.txt
|
|
233
|
-
+++ b/file2.txt
|
|
234
|
-
@@ -5,7 +5,7 @@
|
|
235
|
-
line5
|
|
236
|
-
line6
|
|
237
|
-
-old line7
|
|
238
|
-
+updated line7
|
|
239
|
-
line8
|
|
240
|
-
DIFF
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
This tool is especially useful for making targeted changes to multiple files at once, without having to replace entire file contents.
|
data/docs/ITERATION_SYNTAX.md
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# Using Iteration with Standardized Syntax
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Roast supports powerful iteration constructs with the `repeat` and `each` workflow steps. These features now support a standardized approach to evaluating expressions using the double-curly braces syntax (`{{...}}`).
|
|
6
|
-
|
|
7
|
-
## Syntax Options for Iteration Inputs
|
|
8
|
-
|
|
9
|
-
Both `until` conditions (in `repeat`) and collection expressions (in `each`) accept the following formats:
|
|
10
|
-
|
|
11
|
-
### 1. Ruby Expressions with `{{...}}` Syntax
|
|
12
|
-
|
|
13
|
-
For evaluating Ruby code in the workflow context:
|
|
14
|
-
|
|
15
|
-
```yaml
|
|
16
|
-
# Repeat until a condition is met
|
|
17
|
-
- repeat:
|
|
18
|
-
steps:
|
|
19
|
-
- process_item
|
|
20
|
-
until: "{{output['counter'] >= 5}}"
|
|
21
|
-
max_iterations: 10
|
|
22
|
-
|
|
23
|
-
# Iterate over a collection
|
|
24
|
-
- each: "{{output['items'].filter { |item| item.active? }}}"
|
|
25
|
-
as: "current_item"
|
|
26
|
-
steps:
|
|
27
|
-
- process_item
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 2. Bash Commands with `$(...)` Syntax
|
|
31
|
-
|
|
32
|
-
For executing shell commands and using their results:
|
|
33
|
-
|
|
34
|
-
```yaml
|
|
35
|
-
# Repeat until a command succeeds
|
|
36
|
-
- repeat:
|
|
37
|
-
steps:
|
|
38
|
-
- check_service
|
|
39
|
-
until: "$(curl -s -o /dev/null -w '%{http_code}' http://service.local/ | grep -q 200)"
|
|
40
|
-
max_iterations: 20
|
|
41
|
-
|
|
42
|
-
# Iterate over files returned by a command
|
|
43
|
-
- each: "$(find . -name '*.rb' -type f)"
|
|
44
|
-
as: "current_file"
|
|
45
|
-
steps:
|
|
46
|
-
- process_file
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### 3. Step Names (as strings)
|
|
50
|
-
|
|
51
|
-
For using the result of another step:
|
|
52
|
-
|
|
53
|
-
```yaml
|
|
54
|
-
# Repeat until a step returns a truthy value
|
|
55
|
-
- repeat:
|
|
56
|
-
steps:
|
|
57
|
-
- process_batch
|
|
58
|
-
until: "check_completion"
|
|
59
|
-
max_iterations: 100
|
|
60
|
-
|
|
61
|
-
# Iterate over items returned by a step
|
|
62
|
-
- each: "get_pending_items"
|
|
63
|
-
as: "pending_item"
|
|
64
|
-
steps:
|
|
65
|
-
- process_pending_item
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 4. Prompt Content
|
|
69
|
-
|
|
70
|
-
For defining prompts directly in the workflow:
|
|
71
|
-
|
|
72
|
-
```yaml
|
|
73
|
-
# Using a prompt to determine continuation
|
|
74
|
-
- repeat:
|
|
75
|
-
steps:
|
|
76
|
-
- process_content
|
|
77
|
-
until:
|
|
78
|
-
prompt: prompts/check_completion.md
|
|
79
|
-
model: claude-3-haiku
|
|
80
|
-
max_iterations: 10
|
|
81
|
-
|
|
82
|
-
# Using a prompt to generate a collection
|
|
83
|
-
- each:
|
|
84
|
-
prompt: prompts/generate_test_cases.md
|
|
85
|
-
model: claude-3-haiku
|
|
86
|
-
as: "test_case"
|
|
87
|
-
steps:
|
|
88
|
-
- run_test
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Type Coercion
|
|
92
|
-
|
|
93
|
-
### Smart Defaults
|
|
94
|
-
|
|
95
|
-
Roast applies intelligent defaults for boolean coercion based on the type of expression:
|
|
96
|
-
|
|
97
|
-
- **Ruby expressions** (`{{expr}}`) → Regular boolean coercion (`!!value`)
|
|
98
|
-
- **Bash commands** (`$(cmd)`) → Exit code interpretation (0 = true, non-zero = false)
|
|
99
|
-
- **Inline prompts/step names** → LLM boolean interpretation (analyzes yes/no intent)
|
|
100
|
-
|
|
101
|
-
### Manual Coercion
|
|
102
|
-
|
|
103
|
-
You can override the smart defaults by specifying `coerce_to` directly in the step:
|
|
104
|
-
|
|
105
|
-
```yaml
|
|
106
|
-
# Override prompt to use regular boolean instead of LLM boolean
|
|
107
|
-
- repeat:
|
|
108
|
-
until: "check_condition"
|
|
109
|
-
coerce_to: boolean
|
|
110
|
-
steps:
|
|
111
|
-
- process_item
|
|
112
|
-
|
|
113
|
-
# Force a step result to be treated as iterable
|
|
114
|
-
- each: "get_items"
|
|
115
|
-
as: "item"
|
|
116
|
-
coerce_to: iterable
|
|
117
|
-
steps:
|
|
118
|
-
- process: "{{item}}"
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Available coercion types:
|
|
122
|
-
- `boolean` - Standard Ruby truthiness (`!!` operator)
|
|
123
|
-
- `llm_boolean` - Natural language yes/no interpretation
|
|
124
|
-
- `iterable` - Convert to array (splits strings on newlines)
|
|
125
|
-
|
|
126
|
-
## Migrating Existing Workflows
|
|
127
|
-
|
|
128
|
-
If you're updating existing workflows:
|
|
129
|
-
|
|
130
|
-
1. For Ruby expressions, wrap them in `{{...}}`:
|
|
131
|
-
```yaml
|
|
132
|
-
# Old
|
|
133
|
-
until: "output['counter'] >= 5"
|
|
134
|
-
|
|
135
|
-
# New
|
|
136
|
-
until: "{{output['counter'] >= 5}}"
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
2. Bash commands, step names, and prompts can remain unchanged.
|
|
140
|
-
|
|
141
|
-
## Best Practices
|
|
142
|
-
|
|
143
|
-
- Use `{{...}}` for all Ruby expressions to make them explicit
|
|
144
|
-
- For complex conditions, consider creating a dedicated step that returns a boolean
|
|
145
|
-
- For collections, ensure they return iterable objects (arrays, hashes, etc.)
|
|
146
|
-
- Always set reasonable `max_iterations` limits on repeat loops
|
|
147
|
-
- Use meaningful variable names in `each` loops
|
data/docs/VALIDATION.md
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
# Workflow Validation
|
|
2
|
-
|
|
3
|
-
Roast provides comprehensive validation for workflow configurations to catch errors early and improve the development experience.
|
|
4
|
-
|
|
5
|
-
## Using the Validation Command
|
|
6
|
-
|
|
7
|
-
### Validate a Single Workflow
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# Validate a specific workflow by path
|
|
11
|
-
roast validate path/to/workflow.yml
|
|
12
|
-
|
|
13
|
-
# Or by workflow name (assumes roast/ directory structure)
|
|
14
|
-
roast validate my_workflow
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Validate All Workflows
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# Validate all workflows in the roast/ directory
|
|
21
|
-
roast validate
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Strict Mode
|
|
25
|
-
|
|
26
|
-
Use the `--strict` or `-s` flag to treat warnings as errors:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
roast validate --strict
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Validation Levels
|
|
33
|
-
|
|
34
|
-
### 1. Schema Validation
|
|
35
|
-
|
|
36
|
-
Ensures your workflow conforms to the JSON schema:
|
|
37
|
-
- Required fields (name, tools, steps)
|
|
38
|
-
- Correct data types
|
|
39
|
-
- Valid structure for complex steps (if/then, case/when, each, repeat)
|
|
40
|
-
|
|
41
|
-
### 2. Dependency Checking
|
|
42
|
-
|
|
43
|
-
#### Tool Dependencies
|
|
44
|
-
Validates that all declared tools are available:
|
|
45
|
-
- Checks for tool module existence
|
|
46
|
-
- Supports MCP tool configurations
|
|
47
|
-
- Provides helpful suggestions for typos
|
|
48
|
-
|
|
49
|
-
#### Step References
|
|
50
|
-
Validates that steps referenced in conditions exist:
|
|
51
|
-
- Checks `if`, `unless`, and `case` conditions
|
|
52
|
-
- Distinguishes between step references and expressions
|
|
53
|
-
|
|
54
|
-
#### Resource Dependencies
|
|
55
|
-
Validates file resources:
|
|
56
|
-
- Warns if target files don't exist (unless using glob patterns)
|
|
57
|
-
- Checks for missing prompt files
|
|
58
|
-
|
|
59
|
-
### 3. Configuration Linting
|
|
60
|
-
|
|
61
|
-
#### Naming Conventions
|
|
62
|
-
- Workflows should have descriptive names
|
|
63
|
-
- Step names should use snake_case
|
|
64
|
-
|
|
65
|
-
#### Complexity Checks
|
|
66
|
-
- Warns about workflows with too many steps (>20)
|
|
67
|
-
- Detects excessive nesting depth (>5 levels)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
#### Best Practices
|
|
71
|
-
- Warns about missing error handling
|
|
72
|
-
- Detects unused tool declarations
|
|
73
|
-
|
|
74
|
-
## Error Messages
|
|
75
|
-
|
|
76
|
-
The validator provides clear, actionable error messages:
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
Workflow validation failed with 2 error(s):
|
|
80
|
-
|
|
81
|
-
• Missing required field: 'steps' (Add 'steps' to your workflow configuration)
|
|
82
|
-
• Tool 'Roast::Tools::BashCommand' is not available (Did you mean: Roast::Tools::Bash?)
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Example Workflow
|
|
86
|
-
|
|
87
|
-
Here's an example of a well-validated workflow:
|
|
88
|
-
|
|
89
|
-
```yaml
|
|
90
|
-
name: Data Processing Workflow
|
|
91
|
-
tools:
|
|
92
|
-
- Roast::Tools::Bash
|
|
93
|
-
- Roast::Tools::ReadFile
|
|
94
|
-
- Roast::Tools::WriteFile
|
|
95
|
-
|
|
96
|
-
# Use inputs for sensitive data
|
|
97
|
-
inputs:
|
|
98
|
-
- api_token: "Enter your API token"
|
|
99
|
-
|
|
100
|
-
# Enable error handling
|
|
101
|
-
exit_on_error: true
|
|
102
|
-
|
|
103
|
-
steps:
|
|
104
|
-
- validate_input
|
|
105
|
-
- fetch_data
|
|
106
|
-
- process_data
|
|
107
|
-
- save_results
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Integration with CI/CD
|
|
111
|
-
|
|
112
|
-
You can integrate workflow validation into your CI/CD pipeline:
|
|
113
|
-
|
|
114
|
-
```yaml
|
|
115
|
-
# .github/workflows/validate.yml
|
|
116
|
-
name: Validate Workflows
|
|
117
|
-
on: [push, pull_request]
|
|
118
|
-
|
|
119
|
-
jobs:
|
|
120
|
-
validate:
|
|
121
|
-
runs-on: ubuntu-latest
|
|
122
|
-
steps:
|
|
123
|
-
- uses: actions/checkout@v2
|
|
124
|
-
- uses: ruby/setup-ruby@v1
|
|
125
|
-
with:
|
|
126
|
-
ruby-version: '3.0'
|
|
127
|
-
bundler-cache: true
|
|
128
|
-
- name: Validate all workflows
|
|
129
|
-
run: bundle exec roast validate --strict
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Programmatic Usage
|
|
133
|
-
|
|
134
|
-
You can also use the validator programmatically:
|
|
135
|
-
|
|
136
|
-
```ruby
|
|
137
|
-
require 'roast'
|
|
138
|
-
|
|
139
|
-
yaml_content = File.read('workflow.yml')
|
|
140
|
-
validator = Roast::Workflow::Validators::ValidationOrchestrator.new(yaml_content, 'workflow.yml')
|
|
141
|
-
|
|
142
|
-
if validator.valid?
|
|
143
|
-
puts "Workflow is valid!"
|
|
144
|
-
|
|
145
|
-
# Check for warnings
|
|
146
|
-
validator.warnings.each do |warning|
|
|
147
|
-
puts "Warning: #{warning[:message]}"
|
|
148
|
-
puts " → #{warning[:suggestion]}"
|
|
149
|
-
end
|
|
150
|
-
else
|
|
151
|
-
# Handle errors
|
|
152
|
-
validator.errors.each do |error|
|
|
153
|
-
puts "Error: #{error[:message]}"
|
|
154
|
-
puts " → #{error[:suggestion]}"
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Architecture
|
|
160
|
-
|
|
161
|
-
The validation system follows SOLID principles with a modular design:
|
|
162
|
-
|
|
163
|
-
- **ValidationOrchestrator**: Coordinates all validators and aggregates results
|
|
164
|
-
- **SchemaValidator**: Handles YAML parsing and JSON schema validation
|
|
165
|
-
- **DependencyValidator**: Validates tools, step references, and resources
|
|
166
|
-
- **LintingValidator**: Enforces best practices and code quality standards
|
|
167
|
-
- **StepCollector**: Provides efficient caching for step traversal
|
|
168
|
-
|
|
169
|
-
This architecture makes it easy to extend validation with new rules or customize existing behavior.
|
|
170
|
-
|
|
171
|
-
## Future Enhancements
|
|
172
|
-
|
|
173
|
-
The validation system is designed to be extensible. Future enhancements may include:
|
|
174
|
-
|
|
175
|
-
- Detection of circular dependencies
|
|
176
|
-
- Performance analysis and optimization suggestions
|
|
177
|
-
- Custom validation rules via plugins
|
|
178
|
-
- Integration with language servers for real-time validation
|
data/lib/roast/nil_assertions.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# typed: true
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module Kernel
|
|
5
|
-
#: -> self
|
|
6
|
-
def not_nil!
|
|
7
|
-
self
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
class NilClass
|
|
12
|
-
# @override
|
|
13
|
-
#: -> bot
|
|
14
|
-
def not_nil!
|
|
15
|
-
raise UnexpectedNilError
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class UnexpectedNilError < StandardError
|
|
20
|
-
def initialize(message = "Unexpected nil value encountered.")
|
|
21
|
-
super(message)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|