roast-ai 1.2.0 → 1.3.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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -8
  3. data/README.md +26 -14
  4. data/examples/demo/Gemfile.lock +2 -2
  5. data/examples/plugin-gem-example/Gemfile.lock +4 -4
  6. data/examples/simple_agent.rb +1 -1
  7. data/examples/targets_and_params.rb +12 -0
  8. data/internal/documentation/comments/doc-comments-external.md +5 -3
  9. data/internal/documentation/comments/doc-comments.md +2 -1
  10. data/lib/roast/cog_input_manager.rb +2 -44
  11. data/lib/roast/cogs/agent/config.rb +60 -4
  12. data/lib/roast/cogs/agent/providers/claude/claude_invocation.rb +5 -1
  13. data/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb +218 -18
  14. data/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb +208 -13
  15. data/lib/roast/cogs/agent/providers/pi/pi_invocation.rb +2 -0
  16. data/lib/roast/cogs/chat/config.rb +53 -2
  17. data/lib/roast/cogs/chat.rb +13 -5
  18. data/lib/roast/config_manager.rb +29 -2
  19. data/lib/roast/version.rb +1 -1
  20. data/lib/roast/workflow.rb +10 -7
  21. data/lib/roast/workflow_param_accessors.rb +53 -0
  22. data/sorbet/rbi/shims/lib/roast/cog/config.rbi +251 -0
  23. data/sorbet/rbi/shims/lib/roast/config_context.rbi +5 -1
  24. data/tutorial/01_your_first_workflow/README.md +3 -2
  25. data/tutorial/01_your_first_workflow/configured_chat.rb +1 -1
  26. data/tutorial/02_chaining_cogs/README.md +23 -2
  27. data/tutorial/02_chaining_cogs/code_review.rb +2 -2
  28. data/tutorial/02_chaining_cogs/session_resumption.rb +1 -0
  29. data/tutorial/03_targets_and_params/README.md +10 -1
  30. data/tutorial/04_configuration_options/README.md +19 -0
  31. data/tutorial/README.md +1 -1
  32. metadata +4 -2
@@ -3,15 +3,18 @@
3
3
 
4
4
  module Roast
5
5
  class ConfigManager
6
+ include WorkflowParamAccessors
7
+
6
8
  class ConfigManagerError < Roast::Error; end
7
9
  class ConfigManagerNotPreparedError < ConfigManagerError; end
8
10
  class ConfigManagerAlreadyPreparedError < ConfigManagerError; end
9
11
  class IllegalCogNameError < ConfigManagerError; end
10
12
 
11
- #: (Cog::Registry, Array[^() -> void]) -> void
12
- def initialize(cog_registry, config_procs)
13
+ #: (Cog::Registry, Array[^() -> void], WorkflowContext) -> void
14
+ def initialize(cog_registry, config_procs, workflow_context)
13
15
  @cog_registry = cog_registry
14
16
  @config_procs = config_procs
17
+ @workflow_context = workflow_context
15
18
  @config_context = ConfigContext.new #: ConfigContext
16
19
  @global_config = Cog::Config.new #: Cog::Config
17
20
  @general_configs = {} #: Hash[singleton(Cog), Cog::Config]
@@ -117,6 +120,7 @@ module Roast
117
120
  # NOTE: Sorbet expects the proc passed to instance_exec to be declared as taking an argument
118
121
  # but our cog_config_proc does not get an argument
119
122
  cog_config_proc = cog_config_proc #: as ^(untyped) -> void
123
+ bind_workflow_params(config_object)
120
124
  config_object.instance_exec(&cog_config_proc) if cog_config_proc
121
125
  nil
122
126
  end
@@ -134,8 +138,31 @@ module Roast
134
138
  #: (^() -> void ) -> void
135
139
  def on_global(global_config_proc)
136
140
  global_config_proc = global_config_proc #: as ^(untyped) -> void
141
+ bind_workflow_params(@global_config)
137
142
  @global_config.instance_exec(&global_config_proc) if global_config_proc
138
143
  nil
139
144
  end
145
+
146
+ #: (Cog::Config) -> void
147
+ def bind_workflow_params(object)
148
+ target_bang_method = method(:target!)
149
+ targets_method = method(:targets)
150
+ arg_question_method = method(:arg?)
151
+ args_method = method(:args)
152
+ kwarg_method = method(:kwarg)
153
+ kwarg_bang_method = method(:kwarg!)
154
+ kwarg_question_method = method(:kwarg?)
155
+ kwargs_method = method(:kwargs)
156
+ object.instance_eval do
157
+ define_singleton_method(:target!, proc { target_bang_method.call })
158
+ define_singleton_method(:targets, proc { targets_method.call })
159
+ define_singleton_method(:arg?, proc { |value| arg_question_method.call(value) })
160
+ define_singleton_method(:args, proc { args_method.call })
161
+ define_singleton_method(:kwarg, proc { |key| kwarg_method.call(key) })
162
+ define_singleton_method(:kwarg!, proc { |key| kwarg_bang_method.call(key) })
163
+ define_singleton_method(:kwarg?, proc { |key| kwarg_question_method.call(key) })
164
+ define_singleton_method(:kwargs, proc { kwargs_method.call })
165
+ end
166
+ end
140
167
  end
141
168
  end
data/lib/roast/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Roast
5
- VERSION = "1.2.0"
5
+ VERSION = "1.3.0"
6
6
  end
@@ -19,12 +19,15 @@ module Roast
19
19
  Sync do
20
20
  Dir.mktmpdir("roast-") do |tmpdir|
21
21
  EventMonitor.start!
22
- workflow_dir = Pathname.new(workflow_path).dirname
23
- workflow_context = WorkflowContext.new(params: params, tmpdir: tmpdir, workflow_dir: workflow_dir)
24
- workflow = new(workflow_path, workflow_context)
25
- workflow.prepare!
26
- workflow.start!
27
- EventMonitor.stop!
22
+ begin
23
+ workflow_dir = Pathname.new(workflow_path).dirname
24
+ workflow_context = WorkflowContext.new(params: params, tmpdir: tmpdir, workflow_dir: workflow_dir)
25
+ workflow = new(workflow_path, workflow_context)
26
+ workflow.prepare!
27
+ workflow.start!
28
+ ensure
29
+ EventMonitor.stop! if EventMonitor.running?
30
+ end
28
31
  end
29
32
  end
30
33
  end
@@ -48,7 +51,7 @@ module Roast
48
51
 
49
52
  @preparing = true
50
53
  extract_dsl_procs!
51
- @config_manager = ConfigManager.new(@cog_registry, @config_procs)
54
+ @config_manager = ConfigManager.new(@cog_registry, @config_procs, @workflow_context)
52
55
  @config_manager.not_nil!.prepare!
53
56
  # TODO: probably we should just not pass the params as the top-level scope value anymore
54
57
  @execution_manager = ExecutionManager.new(@cog_registry, @config_manager.not_nil!, @execution_procs, @workflow_context, scope_value: @workflow_context.params)
@@ -0,0 +1,53 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ # @requires_ancestor: Kernel
6
+ module WorkflowParamAccessors
7
+ private
8
+
9
+ #: () -> String
10
+ def target!
11
+ raise ArgumentError, "expected exactly one target" unless @workflow_context.params.targets.length == 1
12
+
13
+ @workflow_context.params.targets.first #: as String
14
+ end
15
+
16
+ #: () -> Array[String]
17
+ def targets
18
+ @workflow_context.params.targets.dup
19
+ end
20
+
21
+ #: (Symbol) -> bool
22
+ def arg?(value)
23
+ @workflow_context.params.args.include?(value)
24
+ end
25
+
26
+ #: () -> Array[Symbol]
27
+ def args
28
+ @workflow_context.params.args.dup
29
+ end
30
+
31
+ #: (Symbol) -> String?
32
+ def kwarg(key)
33
+ @workflow_context.params.kwargs[key]
34
+ end
35
+
36
+ #: (Symbol) -> String
37
+ def kwarg!(key)
38
+ raise ArgumentError, "expected keyword argument '#{key}' to be present" unless @workflow_context.params.kwargs.include?(key)
39
+
40
+ @workflow_context.params.kwargs[key] #: as String
41
+ end
42
+
43
+ #: (Symbol) -> bool
44
+ def kwarg?(key)
45
+ @workflow_context.params.kwargs.include?(key)
46
+ end
47
+
48
+ #: () -> Hash[Symbol, String]
49
+ def kwargs
50
+ @workflow_context.params.kwargs.dup
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,251 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ class Cog
6
+ class Config
7
+ ########################################
8
+ # Workflow Methods
9
+ ########################################
10
+
11
+ # Get the single target value passed to the workflow
12
+ #
13
+ # Returns the target when exactly one target was provided to the workflow. Raises an
14
+ # `ArgumentError` if the workflow was invoked with zero or multiple targets.
15
+ #
16
+ # Targets are file paths, URLs, or other identifiers passed to the workflow when it is
17
+ # invoked. Use this method when your workflow expects exactly one target.
18
+ #
19
+ # ### Invocation
20
+ # Invoke a workflow with a single target like this:
21
+ # ```bash
22
+ # roast execute my_workflow.rb my_target_file.txt
23
+ # ```
24
+ #
25
+ # ### Usage
26
+ # ```ruby
27
+ # config do
28
+ # chat do
29
+ # # Configure based on the single target
30
+ # temperature(target!.end_with?(".md") ? 0.7 : 0.2)
31
+ # end
32
+ # end
33
+ # ```
34
+ #
35
+ # #### See Also
36
+ # - `targets` - Get all targets as an array (works with any number of targets)
37
+ #
38
+ #: () -> String
39
+ def target!; end
40
+
41
+ # Get all targets passed to the workflow
42
+ #
43
+ # Returns an array of all targets provided to the workflow. Works with any number of targets
44
+ # (zero, one, or many). Targets are file paths, URLs, or other identifiers passed when the
45
+ # workflow is invoked.
46
+ #
47
+ # ### Invocation
48
+ # Invoke a workflow with multiple targets like this:
49
+ # ```bash
50
+ # roast execute my_workflow.rb target_one.txt target_two.txt
51
+ # ```
52
+ # or using shell globs like this:
53
+ # ```bash
54
+ # roast execute my_workflow.rb target_*.txt
55
+ # ```
56
+ #
57
+ # ### Usage
58
+ # ```ruby
59
+ # config do
60
+ # map do
61
+ # # Process targets in parallel when there are several
62
+ # parallel! if targets.length > 3
63
+ # end
64
+ # end
65
+ # ```
66
+ #
67
+ # #### See Also
68
+ # - `target!` - Get the single target (raises an error if there isn't exactly one)
69
+ #
70
+ #: () -> Array[String]
71
+ def targets; end
72
+
73
+ # Check if a flag argument was passed to the workflow
74
+ #
75
+ # Returns `true` if the specified flag argument symbol was provided when the workflow
76
+ # was invoked, `false` otherwise.
77
+ #
78
+ # Flag arguments are symbolic flags passed to the workflow (e.g., `retry`, `force`)
79
+ # that enable or modify behavior.
80
+ #
81
+ # ### Invocation
82
+ # Invoke a workflow with flag arguments like this:
83
+ # ```bash
84
+ # roast execute my_workflow.rb [TARGETS] -- retry force
85
+ # ```
86
+ #
87
+ # ### Usage
88
+ # ```ruby
89
+ # config do
90
+ # chat do
91
+ # # Pick a cheaper model when invoked with the `fast` flag
92
+ # model(arg?(:fast) ? "gpt-5.4-nano" : "gpt-5")
93
+ # end
94
+ # end
95
+ # ```
96
+ #
97
+ # #### See Also
98
+ # - `args` - Get all flag arguments as an array
99
+ # - `kwarg?` - Check for keyword arguments (key-value pairs)
100
+ #
101
+ #: (Symbol) -> bool
102
+ def arg?(value); end
103
+
104
+ # Get all flag arguments passed to the workflow
105
+ #
106
+ # Returns an array of all flag argument symbols provided when the workflow was invoked.
107
+ # Flag arguments are symbolic flags (e.g., `retry`, `force`) that enable or modify
108
+ # workflow behavior.
109
+ #
110
+ # ### Invocation
111
+ # Invoke a workflow with flag arguments like this:
112
+ # ```bash
113
+ # roast execute my_workflow.rb [TARGETS] -- retry force
114
+ # ```
115
+ #
116
+ # ### Usage
117
+ # ```ruby
118
+ # config do
119
+ # global do
120
+ # # Show full output whenever any flags were passed
121
+ # display! unless args.empty?
122
+ # end
123
+ # end
124
+ # ```
125
+ #
126
+ # #### See Also
127
+ # - `arg?` - Check if a specific flag argument was provided
128
+ # - `kwargs` - Get all keyword arguments
129
+ #
130
+ #: () -> Array[Symbol]
131
+ def args; end
132
+
133
+ # Get a keyword argument value passed to the workflow
134
+ #
135
+ # Returns the string value for the specified keyword argument key, or `nil` if the key was
136
+ # not provided. Keyword arguments are key-value pairs passed to the workflow for configuration.
137
+ #
138
+ # ### Invocation
139
+ # Invoke a workflow with keyword arguments like this:
140
+ # ```bash
141
+ # roast execute my_workflow.rb [TARGETS] -- name=Samantha project=Roast
142
+ # ```
143
+ #
144
+ # ### Usage
145
+ # ```ruby
146
+ # config do
147
+ # chat do
148
+ # # Use a provided model override, or fall back to a default
149
+ # model(kwarg(:model) || "gpt-5")
150
+ # end
151
+ # end
152
+ # ```
153
+ #
154
+ # #### See Also
155
+ # - `kwarg!` - Get a keyword argument value (raises an error if not provided)
156
+ # - `kwarg?` - Check if a keyword argument was provided
157
+ # - `kwargs` - Get all keyword arguments as a hash
158
+ #
159
+ #: (Symbol) -> String?
160
+ def kwarg(key); end
161
+
162
+ # Get a required keyword argument value passed to the workflow
163
+ #
164
+ # Returns the string value for the specified keyword argument key. Raises an `ArgumentError`
165
+ # if the key was not provided.
166
+ #
167
+ # Use this when your workflow requires a specific keyword argument to function correctly.
168
+ #
169
+ # ### Invocation
170
+ # Invoke a workflow with keyword arguments like this:
171
+ # ```bash
172
+ # roast execute my_workflow.rb [TARGETS] -- name=Samantha project=Roast
173
+ # ```
174
+ #
175
+ # ### Usage
176
+ # ```ruby
177
+ # config do
178
+ # chat do
179
+ # # Require the 'model' keyword argument
180
+ # model(kwarg!(:model))
181
+ # end
182
+ # end
183
+ # ```
184
+ #
185
+ # #### See Also
186
+ # - `kwarg` - Get a keyword argument value (returns nil if not provided)
187
+ # - `kwarg?` - Check if a keyword argument was provided
188
+ # - `kwargs` - Get all keyword arguments as a hash
189
+ #
190
+ #: (Symbol) -> String
191
+ def kwarg!(key); end
192
+
193
+ # Check if a keyword argument was passed to the workflow
194
+ #
195
+ # Returns `true` if the specified keyword argument key was provided when the workflow was
196
+ # invoked, `false` otherwise.
197
+ #
198
+ # ### Invocation
199
+ # Invoke a workflow with keyword arguments like this:
200
+ # ```bash
201
+ # roast execute my_workflow.rb [TARGETS] -- name=Samantha project=Roast
202
+ # ```
203
+ #
204
+ # ### Usage
205
+ # ```ruby
206
+ # config do
207
+ # chat do
208
+ # temperature(0.9) if kwarg?(:creative)
209
+ # end
210
+ # end
211
+ # ```
212
+ #
213
+ # #### See Also
214
+ # - `kwarg` - Get a keyword argument value (returns nil if not provided)
215
+ # - `kwarg!` - Get a keyword argument value (raises an error if not provided)
216
+ # - `kwargs` - Get all keyword arguments as a hash
217
+ #
218
+ #: (Symbol) -> bool
219
+ def kwarg?(key); end
220
+
221
+ # Get all keyword arguments passed to the workflow
222
+ #
223
+ # Returns a hash of all keyword argument key-value pairs provided when the workflow was invoked.
224
+ # All keys are symbols and all values are strings.
225
+ #
226
+ # ### Invocation
227
+ # Invoke a workflow with keyword arguments like this:
228
+ # ```bash
229
+ # roast execute my_workflow.rb [TARGETS] -- name=Samantha project=Roast
230
+ # ```
231
+ #
232
+ # ### Usage
233
+ # ```ruby
234
+ # config do
235
+ # chat do
236
+ # model(kwargs[:model] || "gpt-5")
237
+ # temperature(kwargs[:temperature]&.to_f || 0.3)
238
+ # end
239
+ # end
240
+ # ```
241
+ #
242
+ # #### See Also
243
+ # - `kwarg` - Get a single keyword argument value
244
+ # - `kwarg!` - Get a required keyword argument value
245
+ # - `kwarg?` - Check if a keyword argument was provided
246
+ #
247
+ #: () -> Hash[Symbol, String]
248
+ def kwargs; end
249
+ end
250
+ end
251
+ end
@@ -141,7 +141,7 @@ module Roast
141
141
  #
142
142
  # #### Configure the agent provider
143
143
  # - `provider(symbol)` - Set the agent provider (e.g., `:claude`)
144
- # - `use_default_provider!` - Use the default provider (`:claude`)
144
+ # - `use_default_provider!` - Use the default provider (`:pi`, or `$ROAST_DEFAULT_AGENT_PROVIDER` when set)
145
145
  #
146
146
  # #### Configure the base command used to run the coding agent
147
147
  # - `command(string_or_array)` - Set the base command for invoking the agent
@@ -151,6 +151,10 @@ module Roast
151
151
  # - `model(string)` - Set the model to use
152
152
  # - `use_default_model!` - Use the provider's default model
153
153
  #
154
+ # #### Configure a time limit
155
+ # - `timeout(seconds)` - Kill the agent and fail the cog if it runs longer than this
156
+ # - `no_timeout!` - Let the agent run for as long as it takes (default)
157
+ #
154
158
  # #### Configure the system prompt
155
159
  # - `replace_system_prompt(string)` - Completely replace the agent's default system prompt
156
160
  # - `no_replace_system_prompt!` - Don't replace the default system prompt (default)
@@ -106,7 +106,7 @@ block:
106
106
  config do
107
107
  chat do
108
108
  model "gpt-4o-mini" # Use OpenAI's fast model
109
- provider :openai # Use OpenAI (can also be :anthropic, :perplexity or :gemini)
109
+ provider :openai # Use OpenAI (can also be :anthropic, :perplexity, :gemini or :bedrock)
110
110
  show_prompt! # Display the prompt before sending
111
111
  end
112
112
  end
@@ -129,8 +129,9 @@ Common options you can set:
129
129
  - Anthropic: "claude-haiku-4-5" (default), "claude-sonnet-4-6", "claude-opus-4-7", etc.
130
130
  - Perplexity: "sonar" (default), "sonar-pro", "sonar-deep-research", etc.
131
131
  - Gemini: "gemini-3.1-flash-lite" (default), "gemini-3-flash-preview", "gemini-3.1-pro-preview", etc.
132
+ - Bedrock: "us.anthropic.claude-haiku-4-5-20251001-v1:0" (default), or any other Bedrock model or inference profile ID your account can use
132
133
  - `provider :name` - Which LLM provider
133
- - `:openai`, `:anthropic`, `:perplexity` or `:gemini`
134
+ - `:openai`, `:anthropic`, `:perplexity`, `:gemini` or `:bedrock`
134
135
  - `show_prompt!` - Display the prompt being sent
135
136
  - `show_response!` - Display the response (on by default)
136
137
  - `show_stats!` - Display token usage statistics (on by default)
@@ -10,7 +10,7 @@ config do
10
10
  # Configure all chat cogs in this workflow
11
11
  chat do
12
12
  model "gpt-4o-mini" # Use OpenAI's fast, cost-effective model
13
- provider :openai # Use OpenAI (alternative: :anthropic, :perplexity or :gemini)
13
+ provider :openai # Use OpenAI (alternative: :anthropic, :perplexity, :gemini or :bedrock)
14
14
  show_prompt! # Display the prompt before sending it
15
15
  show_response! # Display the response (this is the default)
16
16
  show_stats! # Display token usage statistics (default)
@@ -127,8 +127,29 @@ execute do
127
127
  end
128
128
  ```
129
129
 
130
- The `agent` cog is backed by a locally installed coding agent -- Anthropic's Claude Code is the default provider.
131
- You'll need to have Claude Code installed and configured correctly for this cog to run.
130
+ The `agent` cog is backed by a locally installed coding agent -- Pi is the default provider (set `ROAST_DEFAULT_AGENT_PROVIDER` to change it globally, e.g. to `claude`).
131
+ You'll need to have Pi installed and configured correctly for this cog to run.
132
+ Roast also supports Claude code, which must be set explicitly in provider or an environment variable.
133
+
134
+ ### Specifying a Model
135
+
136
+ Use a fully-qualified `provider/model` id:
137
+
138
+ ```ruby
139
+ config do
140
+ agent do
141
+ model "anthropic/claude-haiku-4-5-20251001"
142
+ end
143
+ end
144
+ ```
145
+
146
+ Pi requires this qualified form. Claude Code expects a bare model name, so Roast strips the leading
147
+ `anthropic/` prefix automatically when the `:claude` provider is used. Because of this, the same `model`
148
+ string is portable across providers -- you can switch the agent provider without rewriting it.
149
+
150
+ A bare name like `"claude-haiku-4-5-20251001"` (or a shorthand like `"haiku"`) still works when you've set
151
+ `provider :claude`, but it will fail on the default Pi provider, which can't resolve an unqualified model name.
152
+ Prefer the qualified form unless you have a reason not to.
132
153
 
133
154
  ### When to Use Agent vs Chat
134
155
 
@@ -8,8 +8,8 @@
8
8
 
9
9
  config do
10
10
  agent do
11
- model "claude-haiku-4-5-20251001"
12
- provider :claude
11
+ model "anthropic/claude-haiku-4-5-20251001"
12
+ provider :pi
13
13
  end
14
14
 
15
15
  chat do
@@ -13,6 +13,7 @@ config do
13
13
  model "gpt-5.4-nano"
14
14
  end
15
15
  agent do
16
+ provider :claude
16
17
  model "haiku"
17
18
  no_display!
18
19
  show_stats!
@@ -187,6 +187,15 @@ execute do
187
187
  end
188
188
  ```
189
189
 
190
+ Parameter accessors are also available inside cog `config` blocks and the `global` block:
191
+
192
+ ```ruby
193
+ config do
194
+ chat { model(arg?(:fast) ? "gpt-5.4-nano" : "gpt-5") }
195
+ global { abort_on_failure! if arg?(:strict) }
196
+ end
197
+ ```
198
+
190
199
  ## Running the Workflows
191
200
 
192
201
  To run the examples in this chapter:
@@ -220,7 +229,7 @@ bin/roast execute tutorial/03_targets_and_params/multiple_targets.rb \
220
229
  - Use `arg?(:name)` to check if an argument is present
221
230
  - Use `kwarg(:name)` to get a kwarg value (returns nil if missing)
222
231
  - Use `kwarg!(:name)` to require a kwarg (errors if missing)
223
- - All accessors work in any cog's input block
232
+ - All accessors work in any cog's input block, and inside cog `config` / `global` blocks
224
233
 
225
234
  ## What's Next?
226
235
 
@@ -111,6 +111,25 @@ end
111
111
 
112
112
  This is useful when you have multiple similar cogs that need the same configuration.
113
113
 
114
+ ### Configuring Based on Parameters
115
+
116
+ Workflow parameter accessors (`target!`, `targets`, `arg?`, `args`, `kwarg`, `kwarg!`, `kwarg?`, `kwargs`; see Chapter 3)
117
+ are available inside cog `config` blocks and the `global` block, so you can configure cogs based on how the workflow was
118
+ invoked:
119
+
120
+ ```ruby
121
+ config do
122
+ chat do
123
+ # Pick a cheaper model when invoked with the `fast` flag: `-- fast`
124
+ model(arg?(:fast) ? "gpt-5.4-nano" : "gpt-5")
125
+ end
126
+
127
+ global do
128
+ abort_on_failure! if arg?(:strict)
129
+ end
130
+ end
131
+ ```
132
+
114
133
  ## Display Options
115
134
 
116
135
  Control what gets printed during workflow execution using display methods in your `config` block:
data/tutorial/README.md CHANGED
@@ -15,7 +15,7 @@ run coding agents, process data, and so much more.
15
15
  - Ruby installed (3.4.2+)
16
16
  - Roast gem installed
17
17
  - API keys for your AI provider (see [Configuration](https://github.com/Shopify/roast/blob/main/README.md#configuration) for setup)
18
- - Claude Code CLI installed and configured (to use coding agents)
18
+ - Pi CLI installed and configured for default agent examples; Claude Code CLI installed and configured for examples that set `provider :claude`
19
19
 
20
20
  ## How to Use This Tutorial
21
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roast-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
@@ -245,6 +245,7 @@ files:
245
245
  - lib/roast/version.rb
246
246
  - lib/roast/workflow.rb
247
247
  - lib/roast/workflow_context.rb
248
+ - lib/roast/workflow_param_accessors.rb
248
249
  - lib/roast/workflow_params.rb
249
250
  - roast-ai.gemspec
250
251
  - shipit.rubygems.yml
@@ -349,6 +350,7 @@ files:
349
350
  - sorbet/rbi/gems/vcr@6.3.1.rbi
350
351
  - sorbet/rbi/gems/webmock@3.25.1.rbi
351
352
  - sorbet/rbi/gems/zeitwerk@2.7.3.rbi
353
+ - sorbet/rbi/shims/lib/roast/cog/config.rbi
352
354
  - sorbet/rbi/shims/lib/roast/cog_input_context.rbi
353
355
  - sorbet/rbi/shims/lib/roast/config_context.rbi
354
356
  - sorbet/rbi/shims/lib/roast/execution_context.rbi
@@ -406,7 +408,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
406
408
  - !ruby/object:Gem::Version
407
409
  version: '0'
408
410
  requirements: []
409
- rubygems_version: 4.0.14
411
+ rubygems_version: 4.0.21
410
412
  specification_version: 4
411
413
  summary: A framework for executing structured AI workflows in Ruby
412
414
  test_files: []