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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/docs/write-comments.md +1 -1
  3. data/.rubocop.yml +12 -1
  4. data/Gemfile +2 -2
  5. data/Gemfile.lock +149 -34
  6. data/README.md +56 -3
  7. data/examples/agent_with_multiple_prompts.rb +27 -0
  8. data/examples/custom_logging.rb +4 -2
  9. data/examples/demo/Gemfile.lock +49 -15
  10. data/examples/plugin-gem-example/Gemfile.lock +19 -15
  11. data/examples/simple_chat.rb +1 -1
  12. data/examples/simple_pi_agent.rb +18 -0
  13. data/internal/rubocop/cop/roast/no_test_class_nesting.rb +126 -0
  14. data/internal/rubocop/rubocop-roast.yml +6 -0
  15. data/internal/workflows/maintenance/branch_docs_impact.rb +97 -0
  16. data/internal/workflows/maintenance/deprecated_models_docs_updater.rb +78 -0
  17. data/lib/roast/cog/config.rb +1 -1
  18. data/lib/roast/cog/output.rb +2 -1
  19. data/lib/roast/cog/registry.rb +3 -3
  20. data/lib/roast/cog_input_manager.rb +28 -7
  21. data/lib/roast/cogs/agent/config.rb +2 -2
  22. data/lib/roast/cogs/agent/input.rb +20 -22
  23. data/lib/roast/cogs/agent/providers/claude/claude_invocation.rb +13 -5
  24. data/lib/roast/cogs/agent/providers/claude/messages/result_message.rb +1 -1
  25. data/lib/roast/cogs/agent/providers/claude/tool_result.rb +344 -4
  26. data/lib/roast/cogs/agent/providers/claude/tool_use.rb +356 -1
  27. data/lib/roast/cogs/agent/providers/claude.rb +16 -3
  28. data/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb +60 -0
  29. data/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb +57 -0
  30. data/lib/roast/cogs/agent/providers/pi/pi_invocation.rb +352 -0
  31. data/lib/roast/cogs/agent/providers/pi.rb +41 -0
  32. data/lib/roast/cogs/agent/stats.rb +29 -0
  33. data/lib/roast/cogs/agent/usage.rb +22 -0
  34. data/lib/roast/cogs/agent.rb +5 -6
  35. data/lib/roast/cogs/chat/config.rb +28 -2
  36. data/lib/roast/cogs/chat.rb +82 -10
  37. data/lib/roast/event.rb +1 -0
  38. data/lib/roast/event_monitor.rb +35 -3
  39. data/lib/roast/log.rb +21 -0
  40. data/lib/roast/log_formatter.rb +9 -7
  41. data/lib/roast/version.rb +1 -1
  42. data/lib/roast.rb +1 -3
  43. data/roast-ai.gemspec +2 -1
  44. data/sorbet/rbi/gems/activesupport@8.0.2.rbi +549 -383
  45. data/sorbet/rbi/gems/addressable@2.8.7.rbi +46 -44
  46. data/sorbet/rbi/gems/ast@2.4.3.rbi +7 -6
  47. data/sorbet/rbi/gems/async@2.34.0.rbi +21 -3
  48. data/sorbet/rbi/gems/benchmark@0.4.1.rbi +7 -7
  49. data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +198 -1
  50. data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +405 -328
  51. data/sorbet/rbi/gems/console@1.34.2.rbi +2 -2
  52. data/sorbet/rbi/gems/docile@1.4.1.rbi +30 -30
  53. data/sorbet/rbi/gems/drb@2.2.3.rbi +25 -25
  54. data/sorbet/rbi/gems/erubi@1.13.1.rbi +2 -0
  55. data/sorbet/rbi/gems/faraday-net_http@3.4.2.rbi +2 -77
  56. data/sorbet/rbi/gems/faraday-retry@2.3.2.rbi +2 -57
  57. data/sorbet/rbi/gems/faraday@2.14.1.rbi +382 -75
  58. data/sorbet/rbi/gems/guard-compat@1.2.1.rbi +1 -110
  59. data/sorbet/rbi/gems/guard-minitest@2.4.6.rbi +0 -139
  60. data/sorbet/rbi/gems/guard@2.19.1.rbi +38 -38
  61. data/sorbet/rbi/gems/hashdiff@1.2.0.rbi +3 -3
  62. data/sorbet/rbi/gems/i18n@1.14.7.rbi +53 -29
  63. data/sorbet/rbi/gems/io-event@1.14.0.rbi +67 -10
  64. data/sorbet/rbi/gems/json@2.18.1.rbi +227 -5
  65. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +83 -0
  66. data/sorbet/rbi/gems/listen@3.9.0.rbi +7 -7
  67. data/sorbet/rbi/gems/logger@1.7.0.rbi +3 -3
  68. data/sorbet/rbi/gems/lumberjack@1.2.10.rbi +21 -21
  69. data/sorbet/rbi/gems/marcel@1.1.0.rbi +1 -1
  70. data/sorbet/rbi/gems/minitest-rg@5.3.0.rbi +0 -96
  71. data/sorbet/rbi/gems/minitest@5.25.5.rbi +1 -16
  72. data/sorbet/rbi/gems/net-http@0.9.1.rbi +27 -19
  73. data/sorbet/rbi/gems/netrc@0.11.0.rbi +18 -0
  74. data/sorbet/rbi/gems/notiffany@0.1.3.rbi +20 -20
  75. data/sorbet/rbi/gems/ostruct@0.6.2.rbi +149 -15
  76. data/sorbet/rbi/gems/parser@3.3.8.0.rbi +141 -139
  77. data/sorbet/rbi/gems/prism@1.4.0.rbi +922 -864
  78. data/sorbet/rbi/gems/public_suffix@6.0.2.rbi +56 -35
  79. data/sorbet/rbi/gems/racc@1.8.1.rbi +10 -2
  80. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +12 -12
  81. data/sorbet/rbi/gems/rake@13.3.0.rbi +219 -318
  82. data/sorbet/rbi/gems/{rbi@0.3.6.rbi → rbi@0.3.9.rbi} +612 -2267
  83. data/sorbet/rbi/gems/{rbs@3.9.4.rbi → rbs@4.0.0.dev.5.rbi} +2013 -680
  84. data/sorbet/rbi/gems/regexp_parser@2.10.0.rbi +151 -113
  85. data/sorbet/rbi/gems/require-hooks@0.2.3.rbi +110 -0
  86. data/sorbet/rbi/gems/rexml@3.4.2.rbi +24 -51
  87. data/sorbet/rbi/gems/rubocop-ast@1.45.1.rbi +506 -815
  88. data/sorbet/rbi/gems/rubocop-sorbet@0.10.5.rbi +16 -16
  89. data/sorbet/rbi/gems/rubocop@1.77.0.rbi +2692 -2327
  90. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +8 -8
  91. data/sorbet/rbi/gems/ruby_llm@1.8.2.rbi +38 -23
  92. data/sorbet/rbi/gems/securerandom@0.4.1.rbi +1 -1
  93. data/sorbet/rbi/gems/simplecov-html@0.13.2.rbi +2 -131
  94. data/sorbet/rbi/gems/simplecov@0.22.0.rbi +28 -127
  95. data/sorbet/rbi/gems/{spoom@1.6.3.rbi → spoom@1.7.11.rbi} +1139 -2246
  96. data/sorbet/rbi/gems/sqlite3@2.9.0.rbi +91 -1
  97. data/sorbet/rbi/gems/{tapioca@0.16.11.rbi → tapioca@0.17.10.rbi} +721 -835
  98. data/sorbet/rbi/gems/thor@1.4.0.rbi +53 -53
  99. data/sorbet/rbi/gems/tsort@0.2.0.rbi +393 -0
  100. data/sorbet/rbi/gems/type_toolkit@0.0.5.rbi +49 -0
  101. data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +144 -143
  102. data/sorbet/rbi/gems/uri@1.1.1.rbi +7 -7
  103. data/sorbet/rbi/gems/vcr@6.3.1.rbi +53 -36
  104. data/sorbet/rbi/gems/webmock@3.25.1.rbi +38 -13
  105. data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +39 -272
  106. data/sorbet/rbi/shims/lib/roast/execution_context.rbi +3 -3
  107. data/tutorial/01_your_first_workflow/README.md +9 -5
  108. data/tutorial/01_your_first_workflow/configured_chat.rb +1 -1
  109. data/tutorial/02_chaining_cogs/README.md +2 -2
  110. data/tutorial/02_chaining_cogs/code_review.rb +1 -1
  111. data/tutorial/02_chaining_cogs/session_resumption.rb +1 -1
  112. data/tutorial/03_targets_and_params/README.md +1 -1
  113. data/tutorial/04_configuration_options/README.md +2 -2
  114. data/tutorial/08_iterative_workflows/README.md +1 -1
  115. data/tutorial/README.md +1 -1
  116. metadata +39 -17
  117. data/docs/AGENT_STEPS.md +0 -288
  118. data/docs/INSTRUMENTATION.md +0 -243
  119. data/docs/ITERATION_SYNTAX.md +0 -147
  120. data/docs/VALIDATION.md +0 -178
  121. data/lib/roast/nil_assertions.rb +0 -23
  122. /data/internal/documentation/{architectural-notes.md → comments/architectural-notes.md} +0 -0
  123. /data/internal/documentation/{doc-comments-external.md → comments/doc-comments-external.md} +0 -0
  124. /data/internal/documentation/{doc-comments-internal.md → comments/doc-comments-internal.md} +0 -0
  125. /data/internal/documentation/{doc-comments.md → comments/doc-comments.md} +0 -0
@@ -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.
@@ -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
@@ -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