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.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -8
- data/README.md +26 -14
- data/examples/demo/Gemfile.lock +2 -2
- data/examples/plugin-gem-example/Gemfile.lock +4 -4
- data/examples/simple_agent.rb +1 -1
- data/examples/targets_and_params.rb +12 -0
- data/internal/documentation/comments/doc-comments-external.md +5 -3
- data/internal/documentation/comments/doc-comments.md +2 -1
- data/lib/roast/cog_input_manager.rb +2 -44
- data/lib/roast/cogs/agent/config.rb +60 -4
- data/lib/roast/cogs/agent/providers/claude/claude_invocation.rb +5 -1
- data/lib/roast/cogs/agent/providers/pi/messages/tool_call_message.rb +218 -18
- data/lib/roast/cogs/agent/providers/pi/messages/tool_result_message.rb +208 -13
- data/lib/roast/cogs/agent/providers/pi/pi_invocation.rb +2 -0
- data/lib/roast/cogs/chat/config.rb +53 -2
- data/lib/roast/cogs/chat.rb +13 -5
- data/lib/roast/config_manager.rb +29 -2
- data/lib/roast/version.rb +1 -1
- data/lib/roast/workflow.rb +10 -7
- data/lib/roast/workflow_param_accessors.rb +53 -0
- data/sorbet/rbi/shims/lib/roast/cog/config.rbi +251 -0
- data/sorbet/rbi/shims/lib/roast/config_context.rbi +5 -1
- data/tutorial/01_your_first_workflow/README.md +3 -2
- data/tutorial/01_your_first_workflow/configured_chat.rb +1 -1
- data/tutorial/02_chaining_cogs/README.md +23 -2
- data/tutorial/02_chaining_cogs/code_review.rb +2 -2
- data/tutorial/02_chaining_cogs/session_resumption.rb +1 -0
- data/tutorial/03_targets_and_params/README.md +10 -1
- data/tutorial/04_configuration_options/README.md +19 -0
- data/tutorial/README.md +1 -1
- metadata +4 -2
data/lib/roast/config_manager.rb
CHANGED
|
@@ -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
data/lib/roast/workflow.rb
CHANGED
|
@@ -19,12 +19,15 @@ module Roast
|
|
|
19
19
|
Sync do
|
|
20
20
|
Dir.mktmpdir("roast-") do |tmpdir|
|
|
21
21
|
EventMonitor.start!
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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 (`:
|
|
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 :
|
|
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 `:
|
|
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 :
|
|
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 --
|
|
131
|
-
You'll need to have
|
|
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
|
|
|
@@ -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
|
|
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.
|
|
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.
|
|
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: []
|