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
@@ -0,0 +1,147 @@
|
|
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
|
@@ -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
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# Conditional Execution in Roast Workflows
|
2
|
+
|
3
|
+
This example demonstrates how to use conditional execution (`if` and `unless`) in Roast workflows.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
Conditional execution allows workflows to execute different steps based on runtime conditions. This feature supports:
|
8
|
+
|
9
|
+
- `if` conditions - execute steps when a condition is true
|
10
|
+
- `unless` conditions - execute steps when a condition is false
|
11
|
+
- `then` branches - steps to execute when the condition matches
|
12
|
+
- `else` branches - steps to execute when the condition doesn't match (optional, only for `if`)
|
13
|
+
|
14
|
+
## Syntax
|
15
|
+
|
16
|
+
### If Statement
|
17
|
+
|
18
|
+
```yaml
|
19
|
+
- if: "{{expression}}"
|
20
|
+
then:
|
21
|
+
- step1
|
22
|
+
- step2
|
23
|
+
else:
|
24
|
+
- step3
|
25
|
+
- step4
|
26
|
+
```
|
27
|
+
|
28
|
+
### Unless Statement
|
29
|
+
|
30
|
+
```yaml
|
31
|
+
- unless: "{{expression}}"
|
32
|
+
then:
|
33
|
+
- step1
|
34
|
+
- step2
|
35
|
+
```
|
36
|
+
|
37
|
+
## Condition Types
|
38
|
+
|
39
|
+
Conditions can be:
|
40
|
+
|
41
|
+
1. **Ruby Expressions** - Wrapped in `{{...}}`
|
42
|
+
```yaml
|
43
|
+
- if: "{{output.previous_step.success == true}}"
|
44
|
+
```
|
45
|
+
|
46
|
+
2. **Bash Commands** - Wrapped in `$(...)`
|
47
|
+
```yaml
|
48
|
+
- if: "$(test -f /path/to/file && echo true || echo false)"
|
49
|
+
```
|
50
|
+
|
51
|
+
3. **Step References** - Reference to previous step output
|
52
|
+
```yaml
|
53
|
+
- if: "check_condition" # References a previous step
|
54
|
+
```
|
55
|
+
|
56
|
+
4. **File Checks**
|
57
|
+
```yaml
|
58
|
+
- if: "{{File.exist?('/tmp/myfile.txt')}}"
|
59
|
+
```
|
60
|
+
|
61
|
+
## Examples
|
62
|
+
|
63
|
+
### Basic Example
|
64
|
+
|
65
|
+
```yaml
|
66
|
+
name: Conditional Example
|
67
|
+
tools:
|
68
|
+
- Roast::Tools::Cmd
|
69
|
+
|
70
|
+
steps:
|
71
|
+
- check_status: "echo 'success'"
|
72
|
+
|
73
|
+
- if: "{{output.check_status.strip == 'success'}}"
|
74
|
+
then:
|
75
|
+
- success_action: "echo 'Operation succeeded!'"
|
76
|
+
else:
|
77
|
+
- failure_action: "echo 'Operation failed!'"
|
78
|
+
```
|
79
|
+
|
80
|
+
### Unless Example
|
81
|
+
|
82
|
+
```yaml
|
83
|
+
name: Unless Example
|
84
|
+
tools: []
|
85
|
+
|
86
|
+
steps:
|
87
|
+
- check_file: "test -f /tmp/important.txt && echo exists || echo missing"
|
88
|
+
|
89
|
+
- unless: "{{output.check_file.strip == 'exists'}}"
|
90
|
+
then:
|
91
|
+
- create_file: "touch /tmp/important.txt"
|
92
|
+
- notify: "echo 'Created missing file'"
|
93
|
+
```
|
94
|
+
|
95
|
+
### Nested Conditionals
|
96
|
+
|
97
|
+
```yaml
|
98
|
+
name: Nested Conditionals
|
99
|
+
tools: []
|
100
|
+
|
101
|
+
steps:
|
102
|
+
- outer_check: "echo 'true'"
|
103
|
+
- inner_check: "echo 'false'"
|
104
|
+
|
105
|
+
- if: "{{output.outer_check.strip == 'true'}}"
|
106
|
+
then:
|
107
|
+
- if: "{{output.inner_check.strip == 'true'}}"
|
108
|
+
then:
|
109
|
+
- both_true: "echo 'Both conditions are true'"
|
110
|
+
else:
|
111
|
+
- only_outer: "echo 'Only outer condition is true'"
|
112
|
+
else:
|
113
|
+
- outer_false: "echo 'Outer condition is false'"
|
114
|
+
```
|
115
|
+
|
116
|
+
### Platform-Specific Actions
|
117
|
+
|
118
|
+
```yaml
|
119
|
+
name: Platform Detection
|
120
|
+
tools:
|
121
|
+
- Roast::Tools::Cmd
|
122
|
+
|
123
|
+
steps:
|
124
|
+
- detect_os: "uname -s"
|
125
|
+
|
126
|
+
- if: "{{output.detect_os.strip == 'Darwin'}}"
|
127
|
+
then:
|
128
|
+
- mac_setup: "brew --version || echo 'Homebrew not installed'"
|
129
|
+
else:
|
130
|
+
- if: "{{output.detect_os.strip == 'Linux'}}"
|
131
|
+
then:
|
132
|
+
- linux_setup: "apt-get --version || yum --version"
|
133
|
+
else:
|
134
|
+
- unknown_os: "echo 'Unknown operating system'"
|
135
|
+
```
|
136
|
+
|
137
|
+
## Best Practices
|
138
|
+
|
139
|
+
1. **Use Clear Conditions**: Make your conditions explicit and easy to understand
|
140
|
+
2. **Handle Edge Cases**: Always consider what happens when conditions fail
|
141
|
+
3. **Test Both Branches**: Ensure both `then` and `else` branches work correctly
|
142
|
+
4. **Avoid Deep Nesting**: Keep conditional logic simple and readable
|
143
|
+
5. **Use Unless Sparingly**: `unless` can be less intuitive than `if` with negation
|
144
|
+
|
145
|
+
## Debugging
|
146
|
+
|
147
|
+
To debug conditional execution:
|
148
|
+
|
149
|
+
1. Check the workflow output to see which branch was executed
|
150
|
+
2. Look for keys like `if_condition_name` or `unless_condition_name` in the output
|
151
|
+
3. These keys contain information about the condition evaluation and branch taken
|
152
|
+
|
153
|
+
## Running the Example
|
154
|
+
|
155
|
+
```bash
|
156
|
+
# Run the simple conditional example
|
157
|
+
roast execute examples/conditional/simple_workflow.yml
|
158
|
+
|
159
|
+
# Run the full conditional example (requires API configuration)
|
160
|
+
roast execute examples/conditional/workflow.yml
|
161
|
+
```
|
@@ -0,0 +1 @@
|
|
1
|
+
Check if the OS is macOS or Linux and return true if it's macOS, false otherwise.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
name: Simple Conditional Test
|
2
|
+
tools: []
|
3
|
+
|
4
|
+
steps:
|
5
|
+
- set_value: "$(echo 'true')"
|
6
|
+
|
7
|
+
- if: "{{output.set_value.strip == 'true'}}"
|
8
|
+
then:
|
9
|
+
- success: "$(echo 'If condition worked!')"
|
10
|
+
else:
|
11
|
+
- failure: "$(echo 'If condition failed!')"
|
12
|
+
|
13
|
+
- unless: "{{output.set_value.strip == 'false'}}"
|
14
|
+
then:
|
15
|
+
- unless_success: "$(echo 'Unless condition worked!')"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Conditional Execution Example
|
2
|
+
tools:
|
3
|
+
- Roast::Tools::Cmd
|
4
|
+
|
5
|
+
steps:
|
6
|
+
- check_os: "$(uname -s)"
|
7
|
+
|
8
|
+
- if: "{{output.check_os.strip == 'Darwin'}}"
|
9
|
+
then:
|
10
|
+
- mac_message: "$(echo 'Running on macOS!')"
|
11
|
+
- mac_info: "$(sw_vers)"
|
12
|
+
else:
|
13
|
+
- linux_message: "$(echo 'Running on Linux!')"
|
14
|
+
- linux_info: "$(lsb_release -a)"
|
15
|
+
|
16
|
+
- check_file: "$(test -f /tmp/roast_test.txt && echo exists || echo missing)"
|
17
|
+
|
18
|
+
- unless: "{{output.check_file.strip == 'exists'}}"
|
19
|
+
then:
|
20
|
+
- create_file: "$(touch /tmp/roast_test.txt && echo 'File created')"
|
21
|
+
|
22
|
+
- verify_file: "$(ls -la /tmp/roast_test.txt)"
|
23
|
+
- cleanup: "$(rm -f /tmp/roast_test.txt)"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Direct Coerce Syntax
|
2
|
+
|
3
|
+
This example demonstrates the simplified syntax for specifying `coerce_to` and other configuration options directly on iteration steps.
|
4
|
+
|
5
|
+
## Direct Syntax
|
6
|
+
|
7
|
+
Configuration options are specified directly on the step:
|
8
|
+
|
9
|
+
```yaml
|
10
|
+
- repeat:
|
11
|
+
until: "condition"
|
12
|
+
coerce_to: boolean
|
13
|
+
print_response: true
|
14
|
+
model: "claude-3-haiku"
|
15
|
+
steps: [...]
|
16
|
+
```
|
17
|
+
|
18
|
+
## Benefits
|
19
|
+
|
20
|
+
1. **Cleaner YAML** - No unnecessary nesting
|
21
|
+
2. **More intuitive** - Configuration options are at the same level as other step properties
|
22
|
+
3. **Consistent** - Matches how other step properties are specified
|
23
|
+
|
24
|
+
## Supported Options
|
25
|
+
|
26
|
+
All step configuration options can be specified directly:
|
27
|
+
- `coerce_to` - Type coercion (boolean, llm_boolean, iterable)
|
28
|
+
- `print_response` - Whether to print LLM responses
|
29
|
+
- `loop` - Auto-loop behavior
|
30
|
+
- `json` - JSON response mode
|
31
|
+
- `params` - Additional parameters
|
32
|
+
- `model` - Model override
|
@@ -0,0 +1,36 @@
|
|
1
|
+
name: Direct Coerce Syntax Demo
|
2
|
+
description: Demonstrates the simplified coerce_to syntax without config blocks
|
3
|
+
|
4
|
+
steps:
|
5
|
+
# Example 1: Direct coerce_to on repeat
|
6
|
+
- repeat:
|
7
|
+
until: "check_api_ready"
|
8
|
+
coerce_to: boolean # Direct syntax - no config block needed
|
9
|
+
max_iterations: 5
|
10
|
+
steps:
|
11
|
+
- check_api_ready:
|
12
|
+
prompt: "Check if the API endpoint returns a 200 status"
|
13
|
+
- wait: 2
|
14
|
+
|
15
|
+
# Example 2: Direct coerce_to on each
|
16
|
+
- get_data_sources:
|
17
|
+
prompt: "List available data sources, one per line"
|
18
|
+
|
19
|
+
- each: "get_data_sources"
|
20
|
+
as: "source"
|
21
|
+
coerce_to: iterable # Direct syntax
|
22
|
+
steps:
|
23
|
+
- validate_source: "Validating {{source}}..."
|
24
|
+
- process_source:
|
25
|
+
prompt: "Process data from {{source}}"
|
26
|
+
|
27
|
+
# Example 3: Multiple configuration options
|
28
|
+
- repeat:
|
29
|
+
until: "all_tests_pass"
|
30
|
+
coerce_to: llm_boolean # Override default
|
31
|
+
print_response: true # Other options work too
|
32
|
+
max_iterations: 10
|
33
|
+
steps:
|
34
|
+
- run_tests: "$(rake test)"
|
35
|
+
- all_tests_pass:
|
36
|
+
prompt: "Did all tests pass successfully?"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Dot Notation Access Example
|
2
|
+
|
3
|
+
This example demonstrates the new dot notation access feature for workflow outputs.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
With the new dot notation feature, you can access output values using Ruby's method syntax instead of hash syntax:
|
8
|
+
|
9
|
+
### Before (hash syntax):
|
10
|
+
```yaml
|
11
|
+
until: "output[:update_fix_count][:fixes_applied] >= 5 || output[:select_next_issue][:no_issues_left] == true"
|
12
|
+
```
|
13
|
+
|
14
|
+
### After (dot notation):
|
15
|
+
```yaml
|
16
|
+
until: "output.update_fix_count.fixes_applied >= 5 || output.select_next_issue.no_issues_left?"
|
17
|
+
```
|
18
|
+
|
19
|
+
### Even cleaner (omitting output prefix):
|
20
|
+
```yaml
|
21
|
+
until: "update_fix_count.fixes_applied >= 5 || select_next_issue.no_issues_left?"
|
22
|
+
```
|
23
|
+
|
24
|
+
## Features
|
25
|
+
|
26
|
+
1. **Nested access**: `output.step_name.nested.value`
|
27
|
+
2. **Boolean predicates**: `output.step_name.is_complete?` returns false for nil/false values
|
28
|
+
3. **Direct access**: Omit the `output.` prefix for cleaner syntax
|
29
|
+
4. **Backward compatible**: Hash syntax still works (`output[:step_name][:value]`)
|
30
|
+
|
31
|
+
## Example Workflow
|
32
|
+
|
33
|
+
See `workflow.yml` for a complete example that demonstrates:
|
34
|
+
- Setting values in output
|
35
|
+
- Using dot notation in conditions
|
36
|
+
- Boolean predicate methods
|
37
|
+
- Nested value access
|
@@ -0,0 +1,44 @@
|
|
1
|
+
name: dot_notation_example
|
2
|
+
description: Example demonstrating dot notation access for workflow outputs
|
3
|
+
|
4
|
+
steps:
|
5
|
+
initialize:
|
6
|
+
prompt: |
|
7
|
+
Initialize the workflow with some sample data.
|
8
|
+
|
9
|
+
Set output.counter to 0
|
10
|
+
Set output.config.max_iterations to 5
|
11
|
+
Set output.config.enabled to true
|
12
|
+
|
13
|
+
process_items:
|
14
|
+
repeat:
|
15
|
+
# Using dot notation in conditions
|
16
|
+
until: "counter >= config.max_iterations || !config.enabled?"
|
17
|
+
steps:
|
18
|
+
- increment_counter
|
19
|
+
- check_status
|
20
|
+
|
21
|
+
increment_counter:
|
22
|
+
prompt: |
|
23
|
+
Increment the counter by 1.
|
24
|
+
Current counter value: {{counter}}
|
25
|
+
|
26
|
+
Set output.counter to {{counter}} + 1
|
27
|
+
|
28
|
+
check_status:
|
29
|
+
prompt: |
|
30
|
+
Check if we should continue processing.
|
31
|
+
|
32
|
+
Current counter: {{counter}}
|
33
|
+
Max iterations: {{config.max_iterations}}
|
34
|
+
|
35
|
+
If counter is 3, set output.config.enabled to false
|
36
|
+
Set output.status.last_checked to current counter value
|
37
|
+
|
38
|
+
summarize:
|
39
|
+
prompt: |
|
40
|
+
Summarize the results:
|
41
|
+
- Total iterations: {{counter}}
|
42
|
+
- Last checked at: {{status.last_checked}}
|
43
|
+
- Was enabled: {{config.enabled}}
|
44
|
+
- Hit max iterations: {{counter >= config.max_iterations ? "Yes" : "No"}}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Exit on Error Example
|
2
|
+
|
3
|
+
This example demonstrates how to use the `exit_on_error` configuration option to continue workflow execution even when a command fails.
|
4
|
+
|
5
|
+
## Use Case
|
6
|
+
|
7
|
+
When running a linter like RuboCop on a file with syntax errors or style violations, the command will exit with a non-zero status. By default, this would halt the workflow. However, we often want to:
|
8
|
+
|
9
|
+
1. Capture the linter output (including errors)
|
10
|
+
2. Analyze what went wrong
|
11
|
+
3. Apply fixes based on the analysis
|
12
|
+
|
13
|
+
## Configuration
|
14
|
+
|
15
|
+
The key configuration is in the step configuration section:
|
16
|
+
|
17
|
+
```yaml
|
18
|
+
lint_check:
|
19
|
+
exit_on_error: false
|
20
|
+
```
|
21
|
+
|
22
|
+
This tells Roast to:
|
23
|
+
- Continue workflow execution even if the command fails
|
24
|
+
- Capture the full output (stdout and stderr)
|
25
|
+
- Append the exit status to the output
|
26
|
+
|
27
|
+
## Output Format
|
28
|
+
|
29
|
+
When a command fails with `exit_on_error: false`, the output will look like:
|
30
|
+
|
31
|
+
```
|
32
|
+
lib/example.rb:5:3: C: Style/StringLiterals: Prefer double-quoted strings
|
33
|
+
'hello'
|
34
|
+
^^^^^^^
|
35
|
+
[Exit status: 1]
|
36
|
+
```
|
37
|
+
|
38
|
+
This allows subsequent steps to process both the error output and the exit status.
|
39
|
+
|
40
|
+
## Running the Example
|
41
|
+
|
42
|
+
```bash
|
43
|
+
roast execute workflow.yml path/to/file.rb
|
44
|
+
```
|
45
|
+
|
46
|
+
The workflow will:
|
47
|
+
1. Run RuboCop on the file
|
48
|
+
2. Continue even if RuboCop finds issues
|
49
|
+
3. Analyze the linter output
|
50
|
+
4. Apply fixes based on the analysis
|
@@ -0,0 +1,9 @@
|
|
1
|
+
The linter output from the previous step shows issues with the code.
|
2
|
+
Please analyze the output and identify the specific problems that need to be fixed.
|
3
|
+
|
4
|
+
Focus on:
|
5
|
+
- Syntax errors
|
6
|
+
- Style violations
|
7
|
+
- Best practice violations
|
8
|
+
|
9
|
+
Provide a structured list of issues found.
|