roast-ai 0.1.7 → 0.2.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/.github/workflows/ci.yaml +1 -1
- data/CHANGELOG.md +49 -1
- data/CLAUDE.md +20 -0
- data/CLAUDE_NOTES.md +68 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +9 -6
- data/README.md +159 -26
- data/bin/roast +27 -0
- data/docs/ITERATION_SYNTAX.md +147 -0
- data/examples/case_when/README.md +58 -0
- data/examples/case_when/detect_language/prompt.md +16 -0
- data/examples/case_when/workflow.yml +58 -0
- data/examples/conditional/README.md +161 -0
- data/examples/conditional/check_condition/prompt.md +1 -0
- data/examples/conditional/simple_workflow.yml +15 -0
- data/examples/conditional/workflow.yml +23 -0
- data/examples/direct_coerce_syntax/README.md +32 -0
- data/examples/direct_coerce_syntax/workflow.yml +36 -0
- data/examples/dot_notation/README.md +37 -0
- data/examples/dot_notation/workflow.yml +44 -0
- data/examples/exit_on_error/README.md +50 -0
- data/examples/exit_on_error/analyze_lint_output/prompt.md +9 -0
- data/examples/exit_on_error/apply_fixes/prompt.md +2 -0
- data/examples/exit_on_error/workflow.yml +19 -0
- data/examples/grading/workflow.yml +10 -4
- data/examples/iteration/IMPLEMENTATION.md +88 -0
- data/examples/iteration/README.md +68 -0
- data/examples/iteration/analyze_complexity/prompt.md +22 -0
- data/examples/iteration/generate_recommendations/prompt.md +21 -0
- data/examples/iteration/generate_report/prompt.md +129 -0
- data/examples/iteration/implement_fix/prompt.md +25 -0
- data/examples/iteration/prioritize_issues/prompt.md +24 -0
- data/examples/iteration/prompts/analyze_file.md +28 -0
- data/examples/iteration/prompts/generate_summary.md +24 -0
- data/examples/iteration/prompts/update_report.md +29 -0
- data/examples/iteration/prompts/write_report.md +22 -0
- data/examples/iteration/read_file/prompt.md +9 -0
- data/examples/iteration/select_next_issue/prompt.md +25 -0
- data/examples/iteration/simple_workflow.md +39 -0
- data/examples/iteration/simple_workflow.yml +58 -0
- data/examples/iteration/update_fix_count/prompt.md +26 -0
- data/examples/iteration/verify_fix/prompt.md +29 -0
- data/examples/iteration/workflow.yml +42 -0
- data/examples/json_handling/README.md +32 -0
- data/examples/json_handling/workflow.yml +52 -0
- data/examples/openrouter_example/workflow.yml +2 -2
- data/examples/smart_coercion_defaults/README.md +65 -0
- data/examples/smart_coercion_defaults/workflow.yml +44 -0
- data/examples/step_configuration/README.md +87 -0
- data/examples/step_configuration/workflow.yml +60 -0
- data/examples/workflow_generator/README.md +27 -0
- data/examples/workflow_generator/analyze_user_request/prompt.md +34 -0
- data/examples/workflow_generator/create_workflow_files/prompt.md +32 -0
- data/examples/workflow_generator/get_user_input/prompt.md +14 -0
- data/examples/workflow_generator/info_from_roast.rb +22 -0
- data/examples/workflow_generator/workflow.yml +35 -0
- data/lib/roast/errors.rb +9 -0
- data/lib/roast/factories/api_provider_factory.rb +61 -0
- data/lib/roast/helpers/function_caching_interceptor.rb +1 -1
- data/lib/roast/helpers/minitest_coverage_runner.rb +1 -1
- data/lib/roast/helpers/prompt_loader.rb +50 -1
- data/lib/roast/resources/base_resource.rb +7 -0
- data/lib/roast/resources.rb +6 -6
- data/lib/roast/tools/ask_user.rb +40 -0
- data/lib/roast/tools/cmd.rb +1 -1
- data/lib/roast/tools/search_file.rb +1 -1
- data/lib/roast/tools.rb +11 -1
- data/lib/roast/value_objects/api_token.rb +49 -0
- data/lib/roast/value_objects/step_name.rb +39 -0
- data/lib/roast/value_objects/workflow_path.rb +77 -0
- data/lib/roast/value_objects.rb +5 -0
- data/lib/roast/version.rb +1 -1
- data/lib/roast/workflow/api_configuration.rb +61 -0
- data/lib/roast/workflow/base_iteration_step.rb +184 -0
- data/lib/roast/workflow/base_step.rb +44 -27
- data/lib/roast/workflow/base_workflow.rb +76 -73
- data/lib/roast/workflow/case_executor.rb +49 -0
- data/lib/roast/workflow/case_step.rb +82 -0
- data/lib/roast/workflow/command_executor.rb +88 -0
- data/lib/roast/workflow/conditional_executor.rb +50 -0
- data/lib/roast/workflow/conditional_step.rb +59 -0
- data/lib/roast/workflow/configuration.rb +35 -158
- data/lib/roast/workflow/configuration_loader.rb +78 -0
- data/lib/roast/workflow/configuration_parser.rb +13 -248
- data/lib/roast/workflow/context_path_resolver.rb +43 -0
- data/lib/roast/workflow/dot_access_hash.rb +198 -0
- data/lib/roast/workflow/each_step.rb +86 -0
- data/lib/roast/workflow/error_handler.rb +97 -0
- data/lib/roast/workflow/expression_evaluator.rb +78 -0
- data/lib/roast/workflow/expression_utils.rb +36 -0
- data/lib/roast/workflow/file_state_repository.rb +3 -2
- data/lib/roast/workflow/interpolator.rb +34 -0
- data/lib/roast/workflow/iteration_executor.rb +103 -0
- data/lib/roast/workflow/llm_boolean_coercer.rb +55 -0
- data/lib/roast/workflow/output_handler.rb +35 -0
- data/lib/roast/workflow/output_manager.rb +77 -0
- data/lib/roast/workflow/parallel_executor.rb +49 -0
- data/lib/roast/workflow/prompt_step.rb +4 -1
- data/lib/roast/workflow/repeat_step.rb +75 -0
- data/lib/roast/workflow/replay_handler.rb +123 -0
- data/lib/roast/workflow/resource_resolver.rb +77 -0
- data/lib/roast/workflow/session_manager.rb +6 -2
- data/lib/roast/workflow/state_manager.rb +97 -0
- data/lib/roast/workflow/step_executor_coordinator.rb +221 -0
- data/lib/roast/workflow/step_executor_factory.rb +47 -0
- data/lib/roast/workflow/step_executor_registry.rb +79 -0
- data/lib/roast/workflow/step_executors/base_step_executor.rb +23 -0
- data/lib/roast/workflow/step_executors/hash_step_executor.rb +43 -0
- data/lib/roast/workflow/step_executors/parallel_step_executor.rb +54 -0
- data/lib/roast/workflow/step_executors/string_step_executor.rb +29 -0
- data/lib/roast/workflow/step_finder.rb +97 -0
- data/lib/roast/workflow/step_loader.rb +155 -0
- data/lib/roast/workflow/step_orchestrator.rb +45 -0
- data/lib/roast/workflow/step_runner.rb +23 -0
- data/lib/roast/workflow/step_type_resolver.rb +133 -0
- data/lib/roast/workflow/workflow_context.rb +60 -0
- data/lib/roast/workflow/workflow_executor.rb +90 -209
- data/lib/roast/workflow/workflow_initializer.rb +112 -0
- data/lib/roast/workflow/workflow_runner.rb +87 -0
- data/lib/roast/workflow.rb +3 -0
- data/lib/roast.rb +96 -3
- data/roast.gemspec +2 -1
- data/schema/workflow.json +112 -0
- metadata +112 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db58f659180113d7a2bb1bface8da2898be6717033107247156a464b4d14159d
|
4
|
+
data.tar.gz: f14c2caae89fab3353b66ae3eb4457c56975e65c464037a2d401cfca30840d81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88c3f83651c535077bdfe29408a19b874f66f19d8b7e743dd4933922f82fd7aee53ee215968e3d10c0207e92d4c53018a0b190475ba7ac4b70d15cda07a634ff
|
7
|
+
data.tar.gz: 5ebae3dcc5d7d775a3f19ab79ead81d7c11f53fc31b5b20f1db4781a950032e693a2d331fdc4509eb0661c04072f421defcd56d15b9d6ce74f7bfc12357ee1b0
|
data/.github/workflows/ci.yaml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,53 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.2.1]
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Smart coercion defaults for boolean expressions based on step type
|
12
|
+
- Ruby expressions (`{{expr}}`) default to regular boolean coercion
|
13
|
+
- Bash commands (`$(cmd)`) default to exit code interpretation
|
14
|
+
- Inline prompts and regular steps default to "smart" LLM-powered interpretation (looks for truthy or falsy language)
|
15
|
+
- Direct syntax for step configuration - `coerce_to` and other options are now specified directly on iteration steps
|
16
|
+
|
17
|
+
## [0.2.0] - 2025-05-26
|
18
|
+
|
19
|
+
### Added
|
20
|
+
- Conditional execution support with `if` and `unless` clauses for workflow steps
|
21
|
+
- Iteration mechanisms for workflows with `repeat` and `each` constructs (resolving issue #48)
|
22
|
+
- Support for conditional repetition with `until` condition and safety limits
|
23
|
+
- Collection iteration with variable binding for processing lists of items
|
24
|
+
- State persistence for loop iterations to enable resumption after failure
|
25
|
+
- Standardized evaluation of Ruby expressions in iteration constructs using `{{}}` syntax
|
26
|
+
- Support for using bash commands, step names, and Ruby expressions in iteration conditions and collections
|
27
|
+
- Intelligent LLM response to boolean conversion with pattern-based recognition for natural language responses
|
28
|
+
- `exit_on_error` configuration option for command steps to continue workflow on failure (resolving issue #71)
|
29
|
+
- Dot notation access for workflow outputs (e.g., `workflow.output.step.field`)
|
30
|
+
- `--pause` flag for stepping through workflow execution interactively
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
- Automatically add `.gitignore` file to cache directory when created (completing issue #22)
|
34
|
+
- Load initializers before trying to load tools in case custom tools are defined in initializers (thanks @palkan)
|
35
|
+
- Fix loading of targetless workflows (thanks @palkan)
|
36
|
+
- Fix OpenRouter support (thanks @xrendan)
|
37
|
+
- API authentication error handling and model access issues
|
38
|
+
- Conditional step transcript replay regression
|
39
|
+
- DotAccessHash serialization for AI prompts
|
40
|
+
|
41
|
+
### Improved
|
42
|
+
- Enhanced search file tool logging to show full expanded paths instead of relative paths
|
43
|
+
- Major refactoring to eliminate circular dependencies and improve architecture
|
44
|
+
- Extracted command execution logic into dedicated CommandExecutor class
|
45
|
+
- Separated conditional execution from iteration logic for better SOLID compliance
|
46
|
+
- Enhanced error messages for API authentication failures
|
47
|
+
- Replaced all `require_relative` with `require` statements for consistency
|
48
|
+
|
49
|
+
### Changed
|
50
|
+
- Refactored god objects to improve code organization and maintainability
|
51
|
+
- Improved separation of concerns between workflow components
|
52
|
+
|
53
|
+
[0.2.0]: https://github.com/Shopify/roast/compare/v0.1.7...v0.2.0
|
54
|
+
|
8
55
|
## [0.1.7] - 2024-05-16
|
9
56
|
|
10
57
|
### Added
|
@@ -13,6 +60,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
13
60
|
- Comprehensive documentation for all built-in tools
|
14
61
|
- Enhanced README with detailed tool usage examples
|
15
62
|
|
63
|
+
``[0.1.7]: https://github.com/Shopify/roast/compare/v0.1.6...v0.1.7
|
64
|
+
|
16
65
|
## [0.1.6] - 2024-05-15
|
17
66
|
|
18
67
|
### Added
|
@@ -33,7 +82,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
33
82
|
- Improved initializer loading and error handling
|
34
83
|
- Fixed tests for nested .roast folders
|
35
84
|
|
36
|
-
[0.1.7]: https://github.com/Shopify/roast/compare/v0.1.6...v0.1.7
|
37
85
|
[0.1.6]: https://github.com/Shopify/roast/compare/v0.1.5...v0.1.6
|
38
86
|
|
39
87
|
## [0.1.5] - 2024-05-13
|
data/CLAUDE.md
CHANGED
@@ -12,10 +12,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
12
12
|
- Run single test: `bundle exec ruby -Itest test/path/to/test_file.rb`
|
13
13
|
- Lint: `bundle exec rubocop`
|
14
14
|
- Lint (with autocorrect, preferred): `bundle exec rubocop -A`
|
15
|
+
- Whenever you want to run the whole test suite just run `bundle exec rake` to also run linting, and note the linting errors too (most will auto correct but not all)
|
16
|
+
- **Run roast locally**: Use `bin/roast` (not `bundle exec roast` which may use the installed gem)
|
17
|
+
- Alternative: `bundle exec exe/roast`
|
15
18
|
|
16
19
|
## Tech stack
|
17
20
|
- `thor` and `cli-ui` for the CLI tool
|
18
21
|
- Testing: Use Minitest, VCR for HTTP mocking, test files named with `_test.rb` suffix
|
22
|
+
- Prefer using the more literate `test "this is a test description" do` type of testing that we get from extending ActiveSupport::TestCase over the primitive XUnit-style def test_description headings for tests
|
19
23
|
|
20
24
|
## Code Style Guidelines
|
21
25
|
|
@@ -30,6 +34,22 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
30
34
|
- Add runtime dependencies to `roast.gemspec`.
|
31
35
|
- Add development dependencies to `Gemfile`.
|
32
36
|
- Don't ever test private methods directly. Specs should test behavior, not implementation.
|
37
|
+
- I do not like test-specific code embedded in production code, don't ever do that
|
38
|
+
- **Do not use require_relative**
|
39
|
+
- Require statements should always be in alphabetical order
|
40
|
+
- Always leave a blank line after module includes and before the rest of the class
|
41
|
+
|
42
|
+
## Architecture Guidelines
|
43
|
+
|
44
|
+
- **Maintain proper separation of concerns**: Don't mix unrelated concepts in the same class or module
|
45
|
+
- Example: Conditional execution (if/unless) should NOT be mixed with iteration execution (each/repeat)
|
46
|
+
- Each concept should have its own executor class and be handled separately
|
47
|
+
- **Use appropriate inheritance**: Only inherit from a base class if the child truly "is-a" type of the parent
|
48
|
+
- Don't inherit just to reuse some methods - use composition instead
|
49
|
+
- **Follow Single Responsibility Principle**: Each class should have one reason to change
|
50
|
+
- IterationExecutor handles iterations (each, repeat)
|
51
|
+
- ConditionalExecutor handles conditionals (if, unless)
|
52
|
+
- Don't combine different responsibilities in one class
|
33
53
|
|
34
54
|
## Git Workflow Practices
|
35
55
|
|
data/CLAUDE_NOTES.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Important Notes for Claude
|
2
|
+
|
3
|
+
## Roast Workflow Syntax
|
4
|
+
|
5
|
+
### IMPORTANT: No inline configuration for steps!
|
6
|
+
|
7
|
+
Roast workflows DO NOT support inline configuration syntax like this:
|
8
|
+
```yaml
|
9
|
+
# WRONG - This syntax does NOT exist:
|
10
|
+
steps:
|
11
|
+
- step_name:
|
12
|
+
prompt: "some prompt"
|
13
|
+
output: variable_name
|
14
|
+
```
|
15
|
+
|
16
|
+
The correct syntax is:
|
17
|
+
```yaml
|
18
|
+
# CORRECT - Steps are just names or hash assignments:
|
19
|
+
steps:
|
20
|
+
- step_name
|
21
|
+
- variable_name: step_name
|
22
|
+
- variable_name: $(command)
|
23
|
+
```
|
24
|
+
|
25
|
+
### Control flow structures
|
26
|
+
|
27
|
+
Only control flow structures (if/unless, case/when/else, each, repeat) support nested configuration:
|
28
|
+
|
29
|
+
```yaml
|
30
|
+
steps:
|
31
|
+
# Simple step - just the name
|
32
|
+
- detect_language
|
33
|
+
|
34
|
+
# Variable assignment
|
35
|
+
- my_var: detect_language
|
36
|
+
|
37
|
+
# Command execution with assignment
|
38
|
+
- env_type: $(echo $ENVIRONMENT)
|
39
|
+
|
40
|
+
# Control flow - these DO have nested structure
|
41
|
+
- if: "{{ condition }}"
|
42
|
+
then:
|
43
|
+
- step1
|
44
|
+
- step2
|
45
|
+
|
46
|
+
- case: "{{ expression }}"
|
47
|
+
when:
|
48
|
+
value1:
|
49
|
+
- step1
|
50
|
+
value2:
|
51
|
+
- step2
|
52
|
+
else:
|
53
|
+
- step3
|
54
|
+
```
|
55
|
+
|
56
|
+
### Step Configuration
|
57
|
+
|
58
|
+
Step configuration (prompts, outputs, etc.) is handled through:
|
59
|
+
1. File naming conventions (step_name/prompt.md, step_name/output.txt)
|
60
|
+
2. The workflow configuration file itself (tools, target, etc.)
|
61
|
+
|
62
|
+
NOT through inline step configuration in the steps array.
|
63
|
+
|
64
|
+
## Remember:
|
65
|
+
- Steps array contains step names, not step configurations
|
66
|
+
- Only control flow structures have nested configuration
|
67
|
+
- Variable assignment uses hash syntax: `var_name: step_name`
|
68
|
+
- Commands use $() syntax: `var_name: $(command)`
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
roast-ai (0.1
|
4
|
+
roast-ai (0.2.1)
|
5
5
|
activesupport (~> 8.0)
|
6
|
+
cli-ui
|
6
7
|
diff-lcs (~> 1.5)
|
7
8
|
faraday-retry
|
8
9
|
json-schema
|
9
|
-
raix (~> 0.8.
|
10
|
+
raix (~> 0.8.6)
|
10
11
|
thor (~> 1.3)
|
11
12
|
|
12
13
|
GEM
|
@@ -32,9 +33,10 @@ GEM
|
|
32
33
|
benchmark (0.4.0)
|
33
34
|
bigdecimal (3.1.9)
|
34
35
|
cgi (0.4.2)
|
36
|
+
cli-ui (2.3.1)
|
35
37
|
coderay (1.1.3)
|
36
38
|
concurrent-ruby (1.3.5)
|
37
|
-
connection_pool (2.5.
|
39
|
+
connection_pool (2.5.3)
|
38
40
|
crack (1.0.0)
|
39
41
|
bigdecimal
|
40
42
|
rexml
|
@@ -42,7 +44,7 @@ GEM
|
|
42
44
|
dotenv (3.1.8)
|
43
45
|
drb (2.2.1)
|
44
46
|
event_stream_parser (1.0.0)
|
45
|
-
faraday (2.13.
|
47
|
+
faraday (2.13.1)
|
46
48
|
faraday-net_http (>= 2.0, < 3.5)
|
47
49
|
json
|
48
50
|
logger
|
@@ -74,7 +76,7 @@ GEM
|
|
74
76
|
hashdiff (1.1.2)
|
75
77
|
i18n (1.14.7)
|
76
78
|
concurrent-ruby (~> 1.0)
|
77
|
-
json (2.
|
79
|
+
json (2.12.0)
|
78
80
|
json-schema (5.1.1)
|
79
81
|
addressable (~> 2.8)
|
80
82
|
bigdecimal (~> 3.1)
|
@@ -113,7 +115,7 @@ GEM
|
|
113
115
|
public_suffix (6.0.1)
|
114
116
|
racc (1.8.1)
|
115
117
|
rainbow (3.1.1)
|
116
|
-
raix (0.8.
|
118
|
+
raix (0.8.6)
|
117
119
|
activesupport (>= 6.0)
|
118
120
|
faraday-retry (~> 2.0)
|
119
121
|
open_router (~> 0.2)
|
@@ -168,6 +170,7 @@ PLATFORMS
|
|
168
170
|
|
169
171
|
DEPENDENCIES
|
170
172
|
cgi
|
173
|
+
cli-ui
|
171
174
|
dotenv
|
172
175
|
guard
|
173
176
|
guard-minitest
|
data/README.md
CHANGED
@@ -4,6 +4,18 @@
|
|
4
4
|
|
5
5
|
A convention-oriented framework for creating structured AI workflows, maintained by the Augmented Engineering team at Shopify.
|
6
6
|
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```bash
|
10
|
+
$ gem install roast-ai
|
11
|
+
```
|
12
|
+
|
13
|
+
Or add to your Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'roast-ai'
|
17
|
+
```
|
18
|
+
|
7
19
|
## Why you should use Roast
|
8
20
|
|
9
21
|
Roast provides a structured, declarative approach to building AI workflows with:
|
@@ -46,7 +58,7 @@ Each step can have its own prompt file (e.g., `analyze_coverage/prompt.md`) and
|
|
46
58
|
```yaml
|
47
59
|
steps:
|
48
60
|
- prepare_data
|
49
|
-
-
|
61
|
+
-
|
50
62
|
- analyze_code_quality
|
51
63
|
- check_test_coverage
|
52
64
|
- verify_documentation
|
@@ -64,6 +76,42 @@ steps:
|
|
64
76
|
- Summarize the changes made to {{File.basename(file)}}.
|
65
77
|
```
|
66
78
|
|
79
|
+
## Try it
|
80
|
+
|
81
|
+
If you don’t have one already, get an OpenAI key from [here](https://platform.openai.com/settings/organization/api-keys). You will need an account with a credit card, make sure that a basic completion works.
|
82
|
+
|
83
|
+
```bash
|
84
|
+
export OPENAI_API_KEY=sk-proj-....
|
85
|
+
|
86
|
+
curl -H "Content-Type: application/json" \
|
87
|
+
-H "Authorization: Bearer $API_TOKEN" \
|
88
|
+
-d '{"model":"gpt-4.1-mini","messages":[{"role":"user","content":"What is 1+1?"}]}' \
|
89
|
+
https://api.openai.com/v1/chat/completions
|
90
|
+
```
|
91
|
+
|
92
|
+
The [test grading workflow](examples/grading/workflow.md) in this repository is a senior software engineer and testing expert that evaluates the quality of a test based on guidelines.
|
93
|
+
|
94
|
+
Try the workflow.
|
95
|
+
|
96
|
+
```bash
|
97
|
+
./exe/roast execute examples/grading/workflow.yml test/roast/resources_test.rb
|
98
|
+
|
99
|
+
🔥🔥🔥 Everyone loves a good roast 🔥🔥🔥
|
100
|
+
...
|
101
|
+
```
|
102
|
+
|
103
|
+
This will output a test grade.
|
104
|
+
|
105
|
+
```
|
106
|
+
========== TEST GRADE REPORT ==========
|
107
|
+
Test file: test/roast/resources_test.rb
|
108
|
+
|
109
|
+
FINAL GRADE:
|
110
|
+
Score: 80/100
|
111
|
+
Letter Grade: B
|
112
|
+
```
|
113
|
+
Note that you may also need `shadowenv` and `rg`, on MacOS run `brew install shadowenv` and `brew install rg`.
|
114
|
+
|
67
115
|
## How to use Roast
|
68
116
|
|
69
117
|
1. Create a workflow YAML file defining your steps and tools
|
@@ -86,21 +134,21 @@ In Roast, workflows maintain a single conversation with the AI model throughout
|
|
86
134
|
|
87
135
|
Roast supports several types of steps:
|
88
136
|
|
89
|
-
1. **Standard step**: References a directory containing at least a `prompt.md` and optional `output.txt` template. This is the most common type of step.
|
137
|
+
1. **Standard step**: References a directory containing at least a `prompt.md` and optional `output.txt` template. This is the most common type of step.
|
90
138
|
```yaml
|
91
139
|
steps:
|
92
140
|
- analyze_code
|
93
141
|
```
|
94
142
|
|
95
143
|
As an alternative to a directory, you can also implement a custom step as a Ruby class, optionally extending `Roast::Workflow::BaseStep`.
|
96
|
-
|
144
|
+
|
97
145
|
In the example given above, the script would live at `workflow/analyze_code.rb` and should contain a class named `AnalyzeCode` with an initializer that takes a workflow object as context, and a `call` method that will be invoked to run the step. The result of the `call` method will be stored in the `workflow.output` hash.
|
98
146
|
|
99
147
|
|
100
148
|
2. **Parallel steps**: Groups of steps executed concurrently
|
101
149
|
```yaml
|
102
150
|
steps:
|
103
|
-
-
|
151
|
+
-
|
104
152
|
- analyze_code_quality
|
105
153
|
- check_test_coverage
|
106
154
|
```
|
@@ -113,7 +161,102 @@ Roast supports several types of steps:
|
|
113
161
|
```
|
114
162
|
This will execute the command and store the result in the workflow output hash. Explicit key name is optional (`rubocop` in the second line of the example).
|
115
163
|
|
116
|
-
|
164
|
+
By default, commands that exit with non-zero status will halt the workflow. You can configure steps to continue on error:
|
165
|
+
```yaml
|
166
|
+
steps:
|
167
|
+
- lint_check: $(rubocop {{file}})
|
168
|
+
- fix_issues
|
169
|
+
|
170
|
+
# Step configuration
|
171
|
+
lint_check:
|
172
|
+
exit_on_error: false # Continue workflow even if command fails
|
173
|
+
```
|
174
|
+
When `exit_on_error: false`, the command output will include the exit status, allowing subsequent steps to process error information.
|
175
|
+
|
176
|
+
4. **Conditional steps**: Execute different steps based on conditions using `if/unless`
|
177
|
+
```yaml
|
178
|
+
steps:
|
179
|
+
- check_environment:
|
180
|
+
if: "{{ENV['RAILS_ENV'] == 'production'}}"
|
181
|
+
then:
|
182
|
+
- run_production_checks
|
183
|
+
- notify_team
|
184
|
+
else:
|
185
|
+
- run_development_setup
|
186
|
+
|
187
|
+
- verify_dependencies:
|
188
|
+
unless: "$(bundle check)"
|
189
|
+
then:
|
190
|
+
- bundle_install: "$(bundle install)"
|
191
|
+
```
|
192
|
+
|
193
|
+
Conditions can be:
|
194
|
+
- Ruby expressions: `if: "{{output['count'] > 5}}"`
|
195
|
+
- Bash commands: `if: "$(test -f config.yml && echo true)"` (exit code 0 = true)
|
196
|
+
- Step references: `if: "previous_step_name"` (uses the step's output)
|
197
|
+
- Direct values: `if: "true"` or `if: "false"`
|
198
|
+
|
199
|
+
5. **Iteration steps**: Loop over collections or repeat steps with conditions
|
200
|
+
```yaml
|
201
|
+
steps:
|
202
|
+
# Loop over a collection
|
203
|
+
- process_files:
|
204
|
+
each: "{{Dir.glob('**/*.rb')}}"
|
205
|
+
as: current_file
|
206
|
+
steps:
|
207
|
+
- analyze_file
|
208
|
+
- Generate a report for {{current_file}}
|
209
|
+
|
210
|
+
# Repeat until a condition is met
|
211
|
+
- improve_code:
|
212
|
+
repeat:
|
213
|
+
until: "{{output['test_pass'] == true}}"
|
214
|
+
max_iterations: 5
|
215
|
+
steps:
|
216
|
+
- run_tests
|
217
|
+
- fix_issues
|
218
|
+
```
|
219
|
+
|
220
|
+
Each loops support:
|
221
|
+
- Collections from Ruby expressions: `each: "{{[1, 2, 3]}}"`
|
222
|
+
- Command output: `each: "$(ls *.rb)"`
|
223
|
+
- Step references: `each: "file_list"`
|
224
|
+
|
225
|
+
Repeat loops support:
|
226
|
+
- Until conditions: `until: "{{condition}}"`
|
227
|
+
- Maximum iterations: `max_iterations: 10`
|
228
|
+
|
229
|
+
6. **Case/when/else steps**: Select different execution paths based on a value (similar to Ruby's case statement)
|
230
|
+
```yaml
|
231
|
+
steps:
|
232
|
+
- detect_language
|
233
|
+
|
234
|
+
- case: "{{ workflow.output.detect_language }}"
|
235
|
+
when:
|
236
|
+
ruby:
|
237
|
+
- lint_with_rubocop
|
238
|
+
- test_with_rspec
|
239
|
+
javascript:
|
240
|
+
- lint_with_eslint
|
241
|
+
- test_with_jest
|
242
|
+
python:
|
243
|
+
- lint_with_pylint
|
244
|
+
- test_with_pytest
|
245
|
+
else:
|
246
|
+
- analyze_generic
|
247
|
+
- generate_basic_report
|
248
|
+
```
|
249
|
+
|
250
|
+
Case expressions can be:
|
251
|
+
- Workflow outputs: `case: "{{ workflow.output.variable }}"`
|
252
|
+
- Ruby expressions: `case: "{{ count > 10 ? 'high' : 'low' }}"`
|
253
|
+
- Bash commands: `case: "$(echo $ENVIRONMENT)"`
|
254
|
+
- Direct values: `case: "production"`
|
255
|
+
|
256
|
+
The value is compared against each key in the `when` clause, and matching steps are executed.
|
257
|
+
If no match is found, the `else` steps are executed (if provided).
|
258
|
+
|
259
|
+
7. **Raw prompt step**: Simple text prompts for the model without tools
|
117
260
|
```yaml
|
118
261
|
steps:
|
119
262
|
- Summarize the changes made to the codebase.
|
@@ -139,7 +282,7 @@ Roast handles data flow between steps in three primary ways:
|
|
139
282
|
- Generate a summary for {{file}}
|
140
283
|
- result_for_{{file}}: store_results
|
141
284
|
```
|
142
|
-
|
285
|
+
|
143
286
|
Interpolation supports:
|
144
287
|
- Simple variable access: `{{file}}`, `{{resource.target}}`
|
145
288
|
- Access to step outputs: `{{output['previous_step']}}`
|
@@ -150,7 +293,7 @@ For typical AI workflows, the continuous conversation history provides seamless
|
|
150
293
|
### Command Line Options
|
151
294
|
|
152
295
|
#### Basic Options
|
153
|
-
- `-o, --output FILE`: Save results to a file instead of outputting to STDOUT
|
296
|
+
- `-o, --output FILE`: Save results to a file instead of outputting to STDOUT
|
154
297
|
- `-c, --concise`: Use concise output templates (exposed as a boolean flag on `workflow`)
|
155
298
|
- `-v, --verbose`: Show output from all steps as they execute
|
156
299
|
- `-r, --replay STEP_NAME`: Resume a workflow from a specific step, optionally with a specific session timestamp
|
@@ -241,7 +384,7 @@ roast execute workflow.yml -t "$(find . -name '*.rb' -mtime -1)"
|
|
241
384
|
# Process changed test files
|
242
385
|
roast execute workflow.yml -t "$(git diff --name-only HEAD | grep _test.rb)"
|
243
386
|
|
244
|
-
# Process staged files
|
387
|
+
# Process staged files
|
245
388
|
roast execute workflow.yml -t "$(git diff --cached --name-only)"
|
246
389
|
```
|
247
390
|
|
@@ -255,7 +398,7 @@ name: API Integration Workflow
|
|
255
398
|
tools:
|
256
399
|
- Roast::Tools::ReadFile
|
257
400
|
- Roast::Tools::WriteFile
|
258
|
-
|
401
|
+
|
259
402
|
# Dynamic API token using shell command
|
260
403
|
api_token: $(cat ~/.my_token)
|
261
404
|
|
@@ -349,7 +492,9 @@ api_provider: openrouter
|
|
349
492
|
api_token: $(echo $OPENROUTER_API_KEY)
|
350
493
|
```
|
351
494
|
|
352
|
-
|
495
|
+
|
496
|
+
This makes it easy to use environment-specific tokens without hardcoding credentials, especially useful in development environments or CI/CD pipelines. Alternatively, Roast will fall back to `OPENROUTER_API_KEY` or `OPENAI_API_KEY` environment variables based on the specified provider.
|
497
|
+
|
353
498
|
|
354
499
|
### Template Output with ERB
|
355
500
|
|
@@ -372,7 +517,7 @@ This is an example of where the `workflow.output` hash is useful - formatting ou
|
|
372
517
|
|
373
518
|
Available in templates:
|
374
519
|
- `response`: The AI's response for this step
|
375
|
-
- `workflow`: Access to the workflow object
|
520
|
+
- `workflow`: Access to the workflow object
|
376
521
|
- `workflow.output`: The shared hash containing results from all steps when you need programmatic access
|
377
522
|
- `workflow.file`: Current file being processed (or `nil` for targetless workflows)
|
378
523
|
- All workflow configuration options
|
@@ -439,7 +584,7 @@ update_files(
|
|
439
584
|
+new line
|
440
585
|
line2
|
441
586
|
line3
|
442
|
-
|
587
|
+
|
443
588
|
--- a/file2.txt
|
444
589
|
+++ b/file2.txt
|
445
590
|
@@ -5,7 +5,7 @@
|
@@ -556,11 +701,11 @@ module MyProject
|
|
556
701
|
|
557
702
|
def call(commit_sha, include_diff = false)
|
558
703
|
Roast::Helpers::Logger.info("🔍 Analyzing commit: #{commit_sha}\n")
|
559
|
-
|
704
|
+
|
560
705
|
# Your implementation here
|
561
706
|
commit_info = `git show #{commit_sha} --stat`
|
562
707
|
commit_info += "\n\n" + `git show #{commit_sha}` if include_diff
|
563
|
-
|
708
|
+
|
564
709
|
commit_info
|
565
710
|
rescue StandardError => e
|
566
711
|
"Error analyzing commit: #{e.message}".tap do |error_message|
|
@@ -601,18 +746,6 @@ your-project/
|
|
601
746
|
└── ...
|
602
747
|
```
|
603
748
|
|
604
|
-
## Installation
|
605
|
-
|
606
|
-
```bash
|
607
|
-
$ gem install roast-ai
|
608
|
-
```
|
609
|
-
|
610
|
-
Or add to your Gemfile:
|
611
|
-
|
612
|
-
```ruby
|
613
|
-
gem 'roast-ai'
|
614
|
-
```
|
615
|
-
|
616
749
|
## Development
|
617
750
|
|
618
751
|
After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests and linter. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/roast
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'roast' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../.ruby-lsp/Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("roast-ai", "roast")
|