roast-ai 0.2.0 → 0.2.2
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 +5 -1
- data/.gitignore +29 -1
- data/CHANGELOG.md +36 -0
- data/CLAUDE.md +5 -0
- data/CLAUDE_NOTES.md +68 -0
- data/Gemfile.lock +3 -4
- data/README.md +235 -10
- data/docs/ITERATION_SYNTAX.md +31 -3
- 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/direct_coerce_syntax/README.md +32 -0
- data/examples/direct_coerce_syntax/workflow.yml +36 -0
- data/examples/grading/generate_recommendations/output.txt +6 -6
- data/examples/grading/workflow.yml +6 -4
- data/examples/json_handling/README.md +32 -0
- data/examples/json_handling/workflow.yml +52 -0
- data/examples/pre_post_processing/README.md +111 -0
- data/examples/pre_post_processing/analyze_test_file/prompt.md +23 -0
- data/examples/pre_post_processing/improve_test_coverage/prompt.md +17 -0
- data/examples/pre_post_processing/optimize_test_performance/prompt.md +25 -0
- data/examples/pre_post_processing/post_processing/aggregate_metrics/prompt.md +31 -0
- data/examples/pre_post_processing/post_processing/cleanup_environment/prompt.md +28 -0
- data/examples/pre_post_processing/post_processing/generate_summary_report/prompt.md +32 -0
- data/examples/pre_post_processing/post_processing/output.txt +24 -0
- data/examples/pre_post_processing/pre_processing/gather_baseline_metrics/prompt.md +26 -0
- data/examples/pre_post_processing/pre_processing/setup_test_environment/prompt.md +11 -0
- data/examples/pre_post_processing/validate_changes/prompt.md +24 -0
- data/examples/pre_post_processing/workflow.yml +21 -0
- data/examples/single_target_prepost/README.md +36 -0
- data/examples/single_target_prepost/post_processing/output.txt +27 -0
- data/examples/single_target_prepost/pre_processing/gather_dependencies/prompt.md +11 -0
- data/examples/single_target_prepost/workflow.yml +20 -0
- 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/gemfiles/activesupport7.gemfile +4 -0
- data/gemfiles/activesupport8.gemfile +4 -0
- data/lib/roast/tools/grep.rb +13 -4
- data/lib/roast/tools/search_file.rb +2 -2
- data/lib/roast/tools.rb +16 -1
- data/lib/roast/value_objects/uri_base.rb +49 -0
- data/lib/roast/value_objects.rb +1 -0
- data/lib/roast/version.rb +1 -1
- data/lib/roast/workflow/api_configuration.rb +9 -1
- data/lib/roast/workflow/base_iteration_step.rb +22 -3
- data/lib/roast/workflow/base_step.rb +40 -3
- data/lib/roast/workflow/base_workflow.rb +4 -1
- 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 +5 -2
- data/lib/roast/workflow/conditional_step.rb +6 -43
- data/lib/roast/workflow/configuration.rb +4 -2
- data/lib/roast/workflow/configuration_loader.rb +14 -0
- data/lib/roast/workflow/error_handler.rb +18 -0
- data/lib/roast/workflow/expression_evaluator.rb +86 -0
- data/lib/roast/workflow/iteration_executor.rb +18 -0
- data/lib/roast/workflow/prompt_step.rb +4 -1
- data/lib/roast/workflow/repeat_step.rb +2 -2
- data/lib/roast/workflow/step_executor_coordinator.rb +50 -8
- data/lib/roast/workflow/step_loader.rb +21 -7
- data/lib/roast/workflow/step_type_resolver.rb +16 -0
- data/lib/roast/workflow/workflow_execution_context.rb +39 -0
- data/lib/roast/workflow/workflow_executor.rb +22 -2
- data/lib/roast/workflow/workflow_initializer.rb +11 -2
- data/lib/roast/workflow/workflow_runner.rb +127 -5
- data/lib/roast/workflow.rb +1 -0
- data/lib/roast.rb +7 -1
- data/roast.gemspec +1 -1
- data/schema/workflow.json +41 -0
- metadata +40 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64b0bfad5bc7ce9abd2d750ff52695ba997a750556a403e3ab4fc449dfb28946
|
4
|
+
data.tar.gz: 526beebc0ca0697df5ce2f871468fff246440615634ae516439b4c0740f8ce90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0600537a7242638e683a884a0b22b4d5f7fd58bb02d0c7a04240c8720d197a1f4f5e2d5f44c1a7f0335506f7822b51b6c245fd1c5f25627c8a580319d63b1250
|
7
|
+
data.tar.gz: e368630d036c6c3ac6efe00d102ddbf89d438332916ed1adb5aa54fe6cb5f9b34f9adf637c6e36c5baab07015c6f0fb848f675476d4233accd005a98b9630642
|
data/.github/workflows/ci.yaml
CHANGED
@@ -17,10 +17,14 @@ jobs:
|
|
17
17
|
matrix:
|
18
18
|
os: [ubuntu]
|
19
19
|
ruby: ['3.2', '3.3', '3.4']
|
20
|
+
gemfile: ['activesupport7', 'activesupport8']
|
20
21
|
runs-on: ${{ matrix.os }}-latest
|
21
|
-
|
22
|
+
env:
|
23
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
22
24
|
steps:
|
23
25
|
- uses: actions/checkout@v4
|
26
|
+
- name: Install ripgrep
|
27
|
+
run: sudo apt-get update && sudo apt-get install -y ripgrep
|
24
28
|
- uses: ruby/setup-ruby@v1
|
25
29
|
with:
|
26
30
|
ruby-version: ${{ matrix.ruby }}
|
data/.gitignore
CHANGED
@@ -11,4 +11,32 @@
|
|
11
11
|
**/.claude/settings.local.json
|
12
12
|
|
13
13
|
**/CLAUDE.local.md
|
14
|
-
.roast/
|
14
|
+
.roast/
|
15
|
+
|
16
|
+
bin/_guard-core
|
17
|
+
bin/bundle
|
18
|
+
bin/coderay
|
19
|
+
bin/dotenv
|
20
|
+
bin/erb
|
21
|
+
bin/guard
|
22
|
+
bin/htmldiff
|
23
|
+
bin/irb
|
24
|
+
bin/ldiff
|
25
|
+
bin/listen
|
26
|
+
bin/pry
|
27
|
+
bin/racc
|
28
|
+
bin/rake
|
29
|
+
bin/rbs
|
30
|
+
bin/rdbg
|
31
|
+
bin/rdoc
|
32
|
+
bin/ri
|
33
|
+
bin/rubocop
|
34
|
+
bin/ruby-lsp
|
35
|
+
bin/ruby-lsp-check
|
36
|
+
bin/ruby-lsp-launcher
|
37
|
+
bin/ruby-lsp-test-exec
|
38
|
+
bin/ruby-parse
|
39
|
+
bin/ruby-rewrite
|
40
|
+
bin/thor
|
41
|
+
|
42
|
+
gemfiles/*.lock
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,42 @@ 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.2] - 2025-05-29
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Pre/post processing framework for workflows with `pre_processing` and `post_processing` sections (#86)
|
12
|
+
- Support for `output.txt` ERB templates in post-processing phase for custom output formatting
|
13
|
+
- Pre/post processing support for single-target workflows (not just multi-target)
|
14
|
+
- Simplified access to pre-processing data in target workflows (removed `output` intermediary level)
|
15
|
+
- Verbose mode improvements for better debugging experience (#98)
|
16
|
+
- Command outputs are now displayed when using the `--verbose` flag
|
17
|
+
- Commands executed within conditional branches also show output in verbose mode
|
18
|
+
- User-friendly error reporting for workflow failures (#98)
|
19
|
+
- Clear ❌ indicators when commands or steps fail
|
20
|
+
- Command failures show exit status and output (no verbose needed for failures)
|
21
|
+
- Step failures provide helpful context about what might be wrong
|
22
|
+
- Exit handler displays actionable suggestions for resolving issues
|
23
|
+
- Automatic workflow discovery by name (#97)
|
24
|
+
- Can now run workflows by name without full path: `roast execute my_workflow`
|
25
|
+
- Automatically looks for `roast/my_workflow/workflow.yml` in current directory
|
26
|
+
- Configurable base URI for API endpoints (#83)
|
27
|
+
|
28
|
+
### Fixed
|
29
|
+
- Search file tool now correctly prefixes paths when searching (#92)
|
30
|
+
- Support for Ruby projects using ActiveSupport 7.0+ (#95)
|
31
|
+
|
32
|
+
### Changed
|
33
|
+
- ActiveSupport dependency relaxed to >= 7.0 for broader compatibility
|
34
|
+
|
35
|
+
## [0.2.1]
|
36
|
+
|
37
|
+
### Added
|
38
|
+
- Smart coercion defaults for boolean expressions based on step type
|
39
|
+
- Ruby expressions (`{{expr}}`) default to regular boolean coercion
|
40
|
+
- Bash commands (`$(cmd)`) default to exit code interpretation
|
41
|
+
- Inline prompts and regular steps default to "smart" LLM-powered interpretation (looks for truthy or falsy language)
|
42
|
+
- Direct syntax for step configuration - `coerce_to` and other options are now specified directly on iteration steps
|
43
|
+
|
8
44
|
## [0.2.0] - 2025-05-26
|
9
45
|
|
10
46
|
### Added
|
data/CLAUDE.md
CHANGED
@@ -50,6 +50,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
50
50
|
- IterationExecutor handles iterations (each, repeat)
|
51
51
|
- ConditionalExecutor handles conditionals (if, unless)
|
52
52
|
- Don't combine different responsibilities in one class
|
53
|
+
- **Do not implement prompts "inline" using a prompt: attribute nested under step names, that violates the primary design architecture of Roast**
|
54
|
+
|
55
|
+
## Guidance and Expectations
|
56
|
+
|
57
|
+
- Do not decide unilaterally to leave code for the sake of "backwards compatibility"... always run those decisions by me first.
|
53
58
|
|
54
59
|
## Git Workflow Practices
|
55
60
|
|
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.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
roast-ai (0.2.
|
5
|
-
activesupport (
|
4
|
+
roast-ai (0.2.2)
|
5
|
+
activesupport (>= 7.0)
|
6
6
|
cli-ui
|
7
7
|
diff-lcs (~> 1.5)
|
8
8
|
faraday-retry
|
@@ -13,7 +13,7 @@ PATH
|
|
13
13
|
GEM
|
14
14
|
remote: https://rubygems.org/
|
15
15
|
specs:
|
16
|
-
activesupport (
|
16
|
+
activesupport (7.2.2.1)
|
17
17
|
base64
|
18
18
|
benchmark (>= 0.3)
|
19
19
|
bigdecimal
|
@@ -25,7 +25,6 @@ GEM
|
|
25
25
|
minitest (>= 5.1)
|
26
26
|
securerandom (>= 0.3)
|
27
27
|
tzinfo (~> 2.0, >= 2.0.5)
|
28
|
-
uri (>= 0.13.1)
|
29
28
|
addressable (2.8.7)
|
30
29
|
public_suffix (>= 2.0.2, < 7.0)
|
31
30
|
ast (2.4.3)
|
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:
|
@@ -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
|
@@ -76,6 +124,9 @@ roast execute workflow.yml target_file.rb
|
|
76
124
|
|
77
125
|
# Or for a targetless workflow (API calls, data generation, etc.)
|
78
126
|
roast execute workflow.yml
|
127
|
+
|
128
|
+
# Roast will automatically search in `project_root/roast/workflow_name` if the path is incomplete.
|
129
|
+
roast execute my_cool_workflow # Equivalent to `roast execute roast/my_cool_workflow/workflow.yml
|
79
130
|
```
|
80
131
|
|
81
132
|
### Understanding Workflows
|
@@ -178,7 +229,37 @@ Roast supports several types of steps:
|
|
178
229
|
- Until conditions: `until: "{{condition}}"`
|
179
230
|
- Maximum iterations: `max_iterations: 10`
|
180
231
|
|
181
|
-
6. **
|
232
|
+
6. **Case/when/else steps**: Select different execution paths based on a value (similar to Ruby's case statement)
|
233
|
+
```yaml
|
234
|
+
steps:
|
235
|
+
- detect_language
|
236
|
+
|
237
|
+
- case: "{{ workflow.output.detect_language }}"
|
238
|
+
when:
|
239
|
+
ruby:
|
240
|
+
- lint_with_rubocop
|
241
|
+
- test_with_rspec
|
242
|
+
javascript:
|
243
|
+
- lint_with_eslint
|
244
|
+
- test_with_jest
|
245
|
+
python:
|
246
|
+
- lint_with_pylint
|
247
|
+
- test_with_pytest
|
248
|
+
else:
|
249
|
+
- analyze_generic
|
250
|
+
- generate_basic_report
|
251
|
+
```
|
252
|
+
|
253
|
+
Case expressions can be:
|
254
|
+
- Workflow outputs: `case: "{{ workflow.output.variable }}"`
|
255
|
+
- Ruby expressions: `case: "{{ count > 10 ? 'high' : 'low' }}"`
|
256
|
+
- Bash commands: `case: "$(echo $ENVIRONMENT)"`
|
257
|
+
- Direct values: `case: "production"`
|
258
|
+
|
259
|
+
The value is compared against each key in the `when` clause, and matching steps are executed.
|
260
|
+
If no match is found, the `else` steps are executed (if provided).
|
261
|
+
|
262
|
+
7. **Raw prompt step**: Simple text prompts for the model without tools
|
182
263
|
```yaml
|
183
264
|
steps:
|
184
265
|
- Summarize the changes made to the codebase.
|
@@ -398,9 +479,9 @@ Benefits of using OpenRouter:
|
|
398
479
|
|
399
480
|
When using OpenRouter, specify fully qualified model names including the provider prefix (e.g., `anthropic/claude-3-opus-20240229`).
|
400
481
|
|
401
|
-
#### Dynamic API Tokens
|
482
|
+
#### Dynamic API Tokens and URIs
|
402
483
|
|
403
|
-
Roast allows you to dynamically fetch API
|
484
|
+
Roast allows you to dynamically fetch attributes such as API token and URI base (to use with a proxy) via shell commands directly in your workflow configuration:
|
404
485
|
|
405
486
|
```yaml
|
406
487
|
# This will execute the shell command and use the result as the API token
|
@@ -412,8 +493,13 @@ api_token: $(echo $OPENAI_API_KEY)
|
|
412
493
|
# For OpenRouter (requires api_provider setting)
|
413
494
|
api_provider: openrouter
|
414
495
|
api_token: $(echo $OPENROUTER_API_KEY)
|
415
|
-
```
|
416
496
|
|
497
|
+
# Static Proxy URI
|
498
|
+
uri_base: https://proxy.example.com/v1
|
499
|
+
|
500
|
+
# Dynamic Proxy URI
|
501
|
+
uri_base: $(echo $AI_PROXY_URI_BASE)
|
502
|
+
```
|
417
503
|
|
418
504
|
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.
|
419
505
|
|
@@ -668,18 +754,157 @@ your-project/
|
|
668
754
|
└── ...
|
669
755
|
```
|
670
756
|
|
671
|
-
|
757
|
+
### Pre/Post Processing Framework
|
672
758
|
|
673
|
-
|
674
|
-
|
759
|
+
Roast supports pre-processing and post-processing phases for workflows. This enables powerful workflows that need setup/teardown or result aggregation across all processed files.
|
760
|
+
|
761
|
+
#### Overview
|
762
|
+
|
763
|
+
- **Pre-processing**: Steps executed once before any targets are processed
|
764
|
+
- **Post-processing**: Steps executed once after all targets have been processed
|
765
|
+
- **Shared state**: Pre-processing results are available to all subsequent steps
|
766
|
+
- **Result aggregation**: Post-processing has access to all workflow execution results
|
767
|
+
- **Single-target support**: Pre/post processing works with single-target workflows too
|
768
|
+
- **Output templates**: Post-processing supports `output.txt` templates for custom formatting
|
769
|
+
|
770
|
+
#### Configuration
|
771
|
+
|
772
|
+
```yaml
|
773
|
+
name: optimize_tests
|
774
|
+
model: gpt-4o
|
775
|
+
target: "test/**/*_test.rb"
|
776
|
+
|
777
|
+
# Pre-processing steps run once before any test files
|
778
|
+
pre_processing:
|
779
|
+
- gather_baseline_metrics
|
780
|
+
- setup_test_environment
|
781
|
+
|
782
|
+
# Main workflow steps run for each test file
|
783
|
+
steps:
|
784
|
+
- analyze_test
|
785
|
+
- improve_coverage
|
786
|
+
- optimize_performance
|
787
|
+
|
788
|
+
# Post-processing steps run once after all test files
|
789
|
+
post_processing:
|
790
|
+
- aggregate_results
|
791
|
+
- generate_report
|
792
|
+
- cleanup_environment
|
675
793
|
```
|
676
794
|
|
677
|
-
|
795
|
+
#### Directory Structure
|
678
796
|
|
679
|
-
|
680
|
-
|
797
|
+
Pre and post-processing steps follow the same conventions as regular steps but are organized in their own directories:
|
798
|
+
|
799
|
+
```
|
800
|
+
workflow.yml
|
801
|
+
pre_processing/
|
802
|
+
├── gather_baseline_metrics/
|
803
|
+
│ └── prompt.md
|
804
|
+
└── setup_test_environment/
|
805
|
+
└── prompt.md
|
806
|
+
analyze_test/
|
807
|
+
└── prompt.md
|
808
|
+
improve_coverage/
|
809
|
+
└── prompt.md
|
810
|
+
optimize_performance/
|
811
|
+
└── prompt.md
|
812
|
+
post_processing/
|
813
|
+
├── output.txt
|
814
|
+
├── aggregate_results/
|
815
|
+
│ └── prompt.md
|
816
|
+
├── generate_report/
|
817
|
+
│ └── prompt.md
|
818
|
+
└── cleanup_environment/
|
819
|
+
└── prompt.md
|
681
820
|
```
|
682
821
|
|
822
|
+
#### Data Access
|
823
|
+
|
824
|
+
**Pre-processing results in target workflows:**
|
825
|
+
|
826
|
+
Target workflows have access to pre-processing results through the `pre_processing_data` variable with dot notation:
|
827
|
+
|
828
|
+
```erb
|
829
|
+
# In a target workflow step prompt
|
830
|
+
The baseline metrics from pre-processing:
|
831
|
+
<%= pre_processing_data.gather_baseline_metrics %>
|
832
|
+
|
833
|
+
Environment setup details:
|
834
|
+
<%= pre_processing_data.setup_test_environment %>
|
835
|
+
```
|
836
|
+
|
837
|
+
**Post-processing data access:**
|
838
|
+
|
839
|
+
Post-processing steps have access to:
|
840
|
+
|
841
|
+
- `pre_processing`: Direct access to pre-processing results with dot notation
|
842
|
+
- `targets`: Hash of all target workflow results, keyed by file paths
|
843
|
+
|
844
|
+
Example post-processing prompt:
|
845
|
+
```markdown
|
846
|
+
# Generate Summary Report
|
847
|
+
|
848
|
+
Based on the baseline metrics:
|
849
|
+
<%= pre_processing.gather_baseline_metrics %>
|
850
|
+
|
851
|
+
Environment configuration:
|
852
|
+
<%= pre_processing.setup_test_environment %>
|
853
|
+
|
854
|
+
And the results from processing all files:
|
855
|
+
<% targets.each do |file, target| %>
|
856
|
+
File: <%= file %>
|
857
|
+
Analysis results: <%= target.output.analyze_test %>
|
858
|
+
Coverage improvements: <%= target.output.improve_coverage %>
|
859
|
+
Performance optimizations: <%= target.output.optimize_performance %>
|
860
|
+
<% end %>
|
861
|
+
|
862
|
+
Please generate a comprehensive summary report showing:
|
863
|
+
1. Overall improvements achieved
|
864
|
+
2. Files with the most significant changes
|
865
|
+
3. Recommendations for further optimization
|
866
|
+
```
|
867
|
+
|
868
|
+
#### Output Templates
|
869
|
+
|
870
|
+
Post-processing supports custom output formatting using ERB templates. Create an `output.txt` file in your `post_processing` directory to format the final workflow output:
|
871
|
+
|
872
|
+
```erb
|
873
|
+
# post_processing/output.txt
|
874
|
+
=== Workflow Summary Report ===
|
875
|
+
Generated at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
|
876
|
+
|
877
|
+
Environment: <%= pre_processing.setup_test_environment %>
|
878
|
+
|
879
|
+
Files Processed: <%= targets.size %>
|
880
|
+
|
881
|
+
<% targets.each do |file, target| %>
|
882
|
+
- <%= file %>: <%= target.output.analyze_test %>
|
883
|
+
<% end %>
|
884
|
+
|
885
|
+
<%= output.generate_report %>
|
886
|
+
===============================
|
887
|
+
```
|
888
|
+
|
889
|
+
The template has access to:
|
890
|
+
- `pre_processing`: All pre-processing step outputs with dot notation
|
891
|
+
- `targets`: Hash of all target workflow results with dot notation (each target has `.output` and `.final_output`)
|
892
|
+
- `output`: Post-processing step outputs with dot notation
|
893
|
+
|
894
|
+
#### Use Cases
|
895
|
+
|
896
|
+
This pattern is ideal for:
|
897
|
+
|
898
|
+
- **Code migrations**: Setup migration tools, process files, generate migration report
|
899
|
+
- **Test optimization**: Baseline metrics, optimize tests, aggregate improvements
|
900
|
+
- **Documentation generation**: Analyze codebase, generate docs per module, create index
|
901
|
+
- **Dependency updates**: Check versions, update files, verify compatibility
|
902
|
+
- **Security audits**: Setup scanners, check each file, generate security report
|
903
|
+
- **Performance analysis**: Establish baselines, analyze components, summarize findings
|
904
|
+
|
905
|
+
See the [pre/post processing example](examples/pre_post_processing) for a complete working demonstration.
|
906
|
+
|
907
|
+
|
683
908
|
## Development
|
684
909
|
|
685
910
|
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/docs/ITERATION_SYNTAX.md
CHANGED
@@ -90,10 +90,38 @@ For defining prompts directly in the workflow:
|
|
90
90
|
|
91
91
|
## Type Coercion
|
92
92
|
|
93
|
-
|
93
|
+
### Smart Defaults
|
94
94
|
|
95
|
-
|
96
|
-
|
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)
|
97
125
|
|
98
126
|
## Migrating Existing Workflows
|
99
127
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Case/When/Else Example
|
2
|
+
|
3
|
+
This example demonstrates the use of `case/when/else` control flow in Roast workflows.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
The `case/when/else` construct allows you to execute different steps based on the value of an expression, similar to Ruby's case statement or switch statements in other languages.
|
8
|
+
|
9
|
+
## Syntax
|
10
|
+
|
11
|
+
```yaml
|
12
|
+
- case: <expression>
|
13
|
+
when:
|
14
|
+
<value1>:
|
15
|
+
- <steps>
|
16
|
+
<value2>:
|
17
|
+
- <steps>
|
18
|
+
else:
|
19
|
+
- <steps>
|
20
|
+
```
|
21
|
+
|
22
|
+
## Features Demonstrated
|
23
|
+
|
24
|
+
1. **Basic case/when/else**: Detect file language and execute language-specific analysis
|
25
|
+
2. **Bash command evaluation**: Use environment variables to determine deployment strategy
|
26
|
+
3. **Complex expressions**: Use Ruby expressions to categorize numeric values
|
27
|
+
|
28
|
+
## Expression Types
|
29
|
+
|
30
|
+
The `case` expression can be:
|
31
|
+
- A simple string value
|
32
|
+
- An interpolated workflow output: `{{ workflow.output.variable }}`
|
33
|
+
- A Ruby expression: `{{ workflow.output.count > 10 ? 'high' : 'low' }}`
|
34
|
+
- A bash command: `$(echo $ENVIRONMENT)`
|
35
|
+
- A reference to a previous step's output
|
36
|
+
|
37
|
+
## How It Works
|
38
|
+
|
39
|
+
1. The `case` expression is evaluated to produce a value
|
40
|
+
2. The value is compared against each key in the `when` clause
|
41
|
+
3. If a match is found, the steps under that key are executed
|
42
|
+
4. If no match is found and an `else` clause exists, those steps are executed
|
43
|
+
5. If no match is found and no `else` clause exists, execution continues
|
44
|
+
|
45
|
+
## Running the Example
|
46
|
+
|
47
|
+
```bash
|
48
|
+
roast execute examples/case_when/workflow.yml
|
49
|
+
```
|
50
|
+
|
51
|
+
This will process all Ruby, JavaScript, Python, and Go files in the current directory, detecting their language and running appropriate analysis steps.
|
52
|
+
|
53
|
+
## Use Cases
|
54
|
+
|
55
|
+
- **Multi-language projects**: Different linting/testing for different file types
|
56
|
+
- **Environment-specific workflows**: Different deployment steps for prod/staging/dev
|
57
|
+
- **Conditional processing**: Different handling based on file size, complexity, or other metrics
|
58
|
+
- **Error handling**: Different recovery strategies based on error types
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Detect Programming Language
|
2
|
+
|
3
|
+
Based on the file extension and content, determine the primary programming language of this file:
|
4
|
+
- If it's a `.rb` file, return "ruby"
|
5
|
+
- If it's a `.js` file, return "javascript"
|
6
|
+
- If it's a `.py` file, return "python"
|
7
|
+
- If it's a `.go` file, return "go"
|
8
|
+
- Otherwise, return "unknown"
|
9
|
+
|
10
|
+
Return ONLY the language name in lowercase, nothing else.
|
11
|
+
|
12
|
+
File: {{ context.resource_uri }}
|
13
|
+
Content:
|
14
|
+
```
|
15
|
+
{{ context.resource }}
|
16
|
+
```
|
@@ -0,0 +1,58 @@
|
|
1
|
+
name: "Case/When/Else Example"
|
2
|
+
|
3
|
+
tools:
|
4
|
+
- Roast::Tools::Cmd
|
5
|
+
- Roast::Tools::ReadFile
|
6
|
+
- Roast::Tools::WriteFile
|
7
|
+
|
8
|
+
target: "**/*.{rb,js,py,go}"
|
9
|
+
|
10
|
+
steps:
|
11
|
+
- detect_language
|
12
|
+
|
13
|
+
- case: "{{ workflow.output.detect_language }}"
|
14
|
+
when:
|
15
|
+
ruby:
|
16
|
+
- analyze_ruby
|
17
|
+
- generate_ruby_report
|
18
|
+
javascript:
|
19
|
+
- analyze_javascript
|
20
|
+
- generate_js_report
|
21
|
+
python:
|
22
|
+
- analyze_python
|
23
|
+
- generate_python_report
|
24
|
+
go:
|
25
|
+
- analyze_go
|
26
|
+
- generate_go_report
|
27
|
+
else:
|
28
|
+
- analyze_generic
|
29
|
+
- generate_generic_report
|
30
|
+
|
31
|
+
# Another example using bash command for case expression
|
32
|
+
- get_environment: $(echo $ENVIRONMENT || echo "development")
|
33
|
+
|
34
|
+
- case: "{{ workflow.output.get_environment }}"
|
35
|
+
when:
|
36
|
+
production:
|
37
|
+
- production_checks
|
38
|
+
- deploy_production
|
39
|
+
staging:
|
40
|
+
- staging_checks
|
41
|
+
- deploy_staging
|
42
|
+
development:
|
43
|
+
- run_tests
|
44
|
+
- local_deploy
|
45
|
+
else:
|
46
|
+
- unknown_environment
|
47
|
+
|
48
|
+
# Example with numeric case values
|
49
|
+
- count_issues
|
50
|
+
|
51
|
+
- case: "{{ workflow.output.count_issues.to_i > 10 ? 'high' : workflow.output.count_issues.to_i > 5 ? 'medium' : 'low' }}"
|
52
|
+
when:
|
53
|
+
high:
|
54
|
+
- high_priority_alert
|
55
|
+
medium:
|
56
|
+
- medium_priority_notice
|
57
|
+
low:
|
58
|
+
- low_priority_info
|