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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e2c7eb637034ea1c7a97776161d901ddcce583600bb465fd1f403a4866203c4
|
|
4
|
+
data.tar.gz: 194f9efd30453dbf123f16abab80bce99cf713dee8077858c10fa3e80c53d7cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 92f4fc82409d7b59fed96a2ba31ac9c9c4dc9b9744a8645b934223c2fad8f09f5e960dcb8629963af619310516931391b90e0692162dbe42028553e311cb9eb9
|
|
7
|
+
data.tar.gz: 5d12e5e669c9acc5ac3372f621c2627735c0edaf96bf2c674c56ebbee458b69d3c1fc3dea30073045541e06b01c6ece526bcd597de184e5ea6b84fca8a67f2cb
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
roast-ai (1.
|
|
4
|
+
roast-ai (1.3.0)
|
|
5
5
|
activesupport (~> 8.0)
|
|
6
6
|
async (>= 2.34)
|
|
7
7
|
rainbow (>= 3.0.0)
|
|
@@ -193,8 +193,8 @@ GEM
|
|
|
193
193
|
rexml (>= 3.2.6)
|
|
194
194
|
sorbet-static-and-runtime (>= 0.5.10187)
|
|
195
195
|
thor (>= 0.19.2)
|
|
196
|
-
sqlite3 (2.9.
|
|
197
|
-
sqlite3 (2.9.
|
|
196
|
+
sqlite3 (2.9.5-arm64-darwin)
|
|
197
|
+
sqlite3 (2.9.5-x86_64-linux-gnu)
|
|
198
198
|
tapioca (0.17.10)
|
|
199
199
|
benchmark
|
|
200
200
|
bundler (>= 2.2.25)
|
|
@@ -224,7 +224,7 @@ GEM
|
|
|
224
224
|
addressable (>= 2.8.0)
|
|
225
225
|
crack (>= 0.3.2)
|
|
226
226
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
227
|
-
yard (0.9.
|
|
227
|
+
yard (0.9.44)
|
|
228
228
|
yard-sorbet (0.9.0)
|
|
229
229
|
sorbet-runtime
|
|
230
230
|
yard
|
|
@@ -317,7 +317,7 @@ CHECKSUMS
|
|
|
317
317
|
regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
|
|
318
318
|
require-hooks (0.2.3) sha256=224be5b4be0fd2a47cb73286c500da366704a54ec195b6627366380c950efac8
|
|
319
319
|
rexml (3.4.2) sha256=1384268554a37af5da5279431ca3f2f37d46f09ffdd6c95e17cc84c83ea7c417
|
|
320
|
-
roast-ai (1.
|
|
320
|
+
roast-ai (1.3.0)
|
|
321
321
|
rubocop (1.77.0) sha256=1f360b4575ef7a124be27b0dfffa227a2b2d9420d22d4fd8bf179d702bcc88c0
|
|
322
322
|
rubocop-ast (1.45.1) sha256=94042e49adc17f187ba037b33f941ba7398fede77cdf4bffafba95190a473a3e
|
|
323
323
|
rubocop-shopify (2.17.1) sha256=03850eb1a9c4d1f9f0ac1d8d5aa51bb47a149e532cfb5e8d02ac6a90c8800a5f
|
|
@@ -337,8 +337,8 @@ CHECKSUMS
|
|
|
337
337
|
sorbet-static (0.6.12984-x86_64-linux) sha256=39c03af15badb204d640fbc6398bee171f4026377f31cba08cdb381091159c57
|
|
338
338
|
sorbet-static-and-runtime (0.6.12984) sha256=281b39ef61aee83551333df581a8d53737bc39df19e09e9cbe01ca8f8b93826f
|
|
339
339
|
spoom (1.7.11) sha256=4e27384af6d3fde5aadc0287c51e6f76c0802259cbb3b6a67603bf718352f4cf
|
|
340
|
-
sqlite3 (2.9.
|
|
341
|
-
sqlite3 (2.9.
|
|
340
|
+
sqlite3 (2.9.5-arm64-darwin) sha256=d0cf444a70fc9395d513cfbcc1e6719e224aa645314e3824cb0474c721425aa2
|
|
341
|
+
sqlite3 (2.9.5-x86_64-linux-gnu) sha256=233dbcb6714148dd23bc5aeb33e8efd6eac974969564ddd5794c23d5f52b231e
|
|
342
342
|
tapioca (0.17.10) sha256=880a682ca8314f798dd09e9f104134fbf1a713c13be51f7dd4741dd434e6471b
|
|
343
343
|
thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d
|
|
344
344
|
traces (0.18.2) sha256=80f1649cb4daace1d7174b81f3b3b7427af0b93047759ba349960cb8f315e214
|
|
@@ -350,7 +350,7 @@ CHECKSUMS
|
|
|
350
350
|
uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
|
|
351
351
|
vcr (6.3.1) sha256=37b56e157e720446a3f4d2d39919cabef8cb7b6c45936acffd2ef8229fec03ed
|
|
352
352
|
webmock (3.25.1) sha256=ab9d5d9353bcbe6322c83e1c60a7103988efc7b67cd72ffb9012629c3d396323
|
|
353
|
-
yard (0.9.
|
|
353
|
+
yard (0.9.44) sha256=eb087e9b631ccd887b049f303d489963945452d5e2a7eb49a5a74a7cf6887f28
|
|
354
354
|
yard-sorbet (0.9.0) sha256=03d1aa461b9e9c82b886919a13aa3e09fcf4d1852239d2967ed97e92723ffe21
|
|
355
355
|
zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85
|
|
356
356
|
|
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@ A Ruby-based domain-specific language for creating structured AI workflows. Buil
|
|
|
9
9
|
Roast lets you orchestrate AI workflows by combining "cogs" - building blocks that interact with LLMs, run code, execute commands, and process data. Write workflows that:
|
|
10
10
|
|
|
11
11
|
- **Chain AI steps together** - Output from one cog flows seamlessly to the next
|
|
12
|
-
- **Run coding agents locally** - Full filesystem access with Claude Code or other providers
|
|
12
|
+
- **Run coding agents locally** - Full filesystem access with Pi, Claude Code, or other providers
|
|
13
13
|
- **Process collections** - Map operations over arrays with serial or parallel execution
|
|
14
14
|
- **Control flow intelligently** - Conditional execution, iteration, and error handling
|
|
15
15
|
- **Reuse workflow components** - Create modular, parameterized scopes
|
|
@@ -47,8 +47,8 @@ bin/roast execute analyze_codebase.rb
|
|
|
47
47
|
|
|
48
48
|
## Core Cogs
|
|
49
49
|
|
|
50
|
-
- **`chat`** - Send prompts to cloud-based LLMs (OpenAI, Anthropic, Perplexity &
|
|
51
|
-
- **`agent`** - Run local coding agents with filesystem access (Claude Code CLI, etc.)
|
|
50
|
+
- **`chat`** - Send prompts to cloud-based LLMs (OpenAI, Anthropic, Perplexity, Gemini & Amazon Bedrock)
|
|
51
|
+
- **`agent`** - Run local coding agents with filesystem access (Pi CLI, Claude Code CLI, etc.)
|
|
52
52
|
- **`ruby`** - Execute custom Ruby code within workflows
|
|
53
53
|
- **`cmd`** - Run shell commands and capture output
|
|
54
54
|
- **`map`** - Process collections in serial or parallel
|
|
@@ -70,34 +70,45 @@ gem 'roast-ai'
|
|
|
70
70
|
|
|
71
71
|
- Ruby 3.0+
|
|
72
72
|
- API keys or local credentials for your AI provider
|
|
73
|
-
-
|
|
73
|
+
- Pi CLI installed (for the default agent provider)
|
|
74
74
|
|
|
75
75
|
## Provider Configuration
|
|
76
76
|
|
|
77
|
-
Roast provider settings are configured in workflow `config` blocks.
|
|
77
|
+
Roast provider settings are configured in workflow `config` blocks. To change the default **chat** provider without editing each workflow, set the `ROAST_DEFAULT_CHAT_PROVIDER` environment variable (e.g. `export ROAST_DEFAULT_CHAT_PROVIDER=anthropic`). To change the default **agent** provider, set `ROAST_DEFAULT_AGENT_PROVIDER`. A `provider` set in a workflow's `config` always takes precedence over these variables, and an invalid value raises an error.
|
|
78
78
|
|
|
79
79
|
### Chat cog
|
|
80
80
|
|
|
81
|
-
The `chat` cog
|
|
81
|
+
The `chat` cog supports **OpenAI**, **Anthropic**, **Perplexity**, **Gemini**, and **Amazon Bedrock**. It defaults to `:openai` (override globally with `ROAST_DEFAULT_CHAT_PROVIDER`). Each provider reads its API key from a provider-specific environment variable:
|
|
82
|
+
|
|
83
|
+
| Provider | API key env var | Base URL env var |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `:openai` | `OPENAI_API_KEY` | `OPENAI_API_BASE` |
|
|
86
|
+
| `:anthropic` | `ANTHROPIC_API_KEY` | `ANTHROPIC_API_BASE` |
|
|
87
|
+
| `:perplexity` | `PERPLEXITY_API_KEY` | — |
|
|
88
|
+
| `:gemini` | `GEMINI_API_KEY` | `GEMINI_API_BASE` |
|
|
89
|
+
| `:bedrock` | `AWS_ACCESS_KEY_ID` | — |
|
|
90
|
+
|
|
91
|
+
The `:bedrock` provider also reads `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` (for temporary credentials) and `AWS_REGION` from the environment. It does not read AWS profiles. It reads every credential from the environment, so do not use `api_key` with `:bedrock`: it replaces only the access key ID and can pair it with a mismatched `AWS_SECRET_ACCESS_KEY`. The default model is a `us.` inference profile, so accounts outside the US must set `model` in the `chat` config block. To use AWS SSO, export temporary credentials first:
|
|
82
92
|
|
|
83
93
|
```bash
|
|
84
|
-
export
|
|
94
|
+
eval "$(aws configure export-credentials --profile my-profile --format env)"
|
|
95
|
+
export AWS_REGION=us-west-2
|
|
85
96
|
```
|
|
86
97
|
|
|
87
|
-
You can
|
|
98
|
+
You can configure the provider directly in a workflow:
|
|
88
99
|
|
|
89
100
|
```ruby
|
|
90
101
|
config do
|
|
91
102
|
chat do
|
|
92
|
-
provider :
|
|
93
|
-
model "
|
|
103
|
+
provider :anthropic
|
|
104
|
+
model "claude-haiku-4-5"
|
|
94
105
|
end
|
|
95
106
|
end
|
|
96
107
|
```
|
|
97
108
|
|
|
98
109
|
### Agent cog
|
|
99
110
|
|
|
100
|
-
The `agent` cog runs local agent CLIs. It defaults to `:
|
|
111
|
+
The `agent` cog runs local agent CLIs. It defaults to `:pi` (override globally with `ROAST_DEFAULT_AGENT_PROVIDER`) and currently supports:
|
|
101
112
|
|
|
102
113
|
- `:claude` - Claude Code CLI
|
|
103
114
|
- `:pi` - Pi CLI
|
|
@@ -116,14 +127,14 @@ Agent providers must be installed and authenticated according to their own CLI r
|
|
|
116
127
|
|
|
117
128
|
## Configuration
|
|
118
129
|
|
|
119
|
-
Roast currently supports
|
|
130
|
+
Roast currently supports five LLM providers for the `chat` cog: **OpenAI**, **Anthropic**, **Perplexity**, **Gemini** and **Amazon Bedrock**.
|
|
120
131
|
|
|
121
|
-
- Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY` and/or `GEMINI_API_KEY` in your environment.
|
|
132
|
+
- Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY` and/or `GEMINI_API_KEY` in your environment. For Bedrock, set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION` instead.
|
|
122
133
|
- Optionally set `OPENAI_API_BASE`, `ANTHROPIC_API_BASE` and/or `GEMINI_API_BASE` to override the default endpoint. Perplexity does not support base URL override.
|
|
123
134
|
|
|
124
135
|
The default model is set per-provider and can only be overridden inside a `config` block. See the [tutorial](https://github.com/Shopify/roast/blob/main/tutorial/01_your_first_workflow/README.md#adding-configuration) for examples.
|
|
125
136
|
|
|
126
|
-
The `agent` cog is powered by the
|
|
137
|
+
The `agent` cog is powered by the Pi CLI by default, which handles its own authentication.
|
|
127
138
|
|
|
128
139
|
## Getting Started
|
|
129
140
|
|
|
@@ -159,6 +170,7 @@ class and method comments on the relevant classes.
|
|
|
159
170
|
* [Additional Example Workflows]([https://github.com/Shopify/roast/tree/main/examples](https://github.com/Shopify/roast/tree/main/examples)) (these comprise the Roast end-to-end test suite)
|
|
160
171
|
* __Configuation__
|
|
161
172
|
* [General configuration block: `config-context.rbi`](https://github.com/Shopify/roast/blob/main/sorbet/rbi/shims/lib/roast/config_context.rbi)
|
|
173
|
+
* [Workflow params in cog config blocks: `cog/config.rbi`](https://github.com/Shopify/roast/blob/main/sorbet/rbi/shims/lib/roast/cog/config.rbi)
|
|
162
174
|
* [Global cog configuration: `cog/config.rb`](https://github.com/Shopify/roast/blob/main/lib/roast/cog/config.rb)
|
|
163
175
|
* [Agent cog configuration: `agent/config.rb`](https://github.com/Shopify/roast/blob/main/lib/roast/cogs/agent/config.rb)
|
|
164
176
|
* [Chat cog configuration: `chat/config.rb`](https://github.com/Shopify/roast/blob/main/lib/roast/cogs/chat/config.rb)
|
data/examples/demo/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ../..
|
|
3
3
|
specs:
|
|
4
|
-
roast-ai (1.
|
|
4
|
+
roast-ai (1.3.0)
|
|
5
5
|
activesupport (~> 8.0)
|
|
6
6
|
async (>= 2.34)
|
|
7
7
|
rainbow (>= 3.0.0)
|
|
@@ -66,7 +66,7 @@ GEM
|
|
|
66
66
|
i18n (1.14.8)
|
|
67
67
|
concurrent-ruby (~> 1.0)
|
|
68
68
|
io-event (1.14.0)
|
|
69
|
-
json (2.
|
|
69
|
+
json (2.21.2)
|
|
70
70
|
language_server-protocol (3.17.0.5)
|
|
71
71
|
lint_roller (1.1.0)
|
|
72
72
|
logger (1.7.0)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ../..
|
|
3
3
|
specs:
|
|
4
|
-
roast-ai (1.
|
|
4
|
+
roast-ai (1.3.0)
|
|
5
5
|
activesupport (~> 8.0)
|
|
6
6
|
async (>= 2.34)
|
|
7
7
|
rainbow (>= 3.0.0)
|
|
@@ -51,13 +51,13 @@ GEM
|
|
|
51
51
|
drb (2.2.3)
|
|
52
52
|
erb (6.0.1.1)
|
|
53
53
|
event_stream_parser (1.0.0)
|
|
54
|
-
faraday (2.14.
|
|
54
|
+
faraday (2.14.3)
|
|
55
55
|
faraday-net_http (>= 2.0, < 3.5)
|
|
56
56
|
json
|
|
57
57
|
logger
|
|
58
58
|
faraday-multipart (1.1.1)
|
|
59
59
|
multipart-post (~> 2.0)
|
|
60
|
-
faraday-net_http (3.4.
|
|
60
|
+
faraday-net_http (3.4.4)
|
|
61
61
|
net-http (~> 0.5)
|
|
62
62
|
faraday-retry (2.3.2)
|
|
63
63
|
faraday (~> 2.0)
|
|
@@ -73,7 +73,7 @@ GEM
|
|
|
73
73
|
pp (>= 0.6.0)
|
|
74
74
|
rdoc (>= 4.0.0)
|
|
75
75
|
reline (>= 0.4.2)
|
|
76
|
-
json (2.
|
|
76
|
+
json (2.21.2)
|
|
77
77
|
language_server-protocol (3.17.0.5)
|
|
78
78
|
lint_roller (1.1.0)
|
|
79
79
|
logger (1.7.0)
|
data/examples/simple_agent.rb
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
#: self as Roast::Workflow
|
|
5
5
|
|
|
6
6
|
config do
|
|
7
|
+
# Workflow params are available inside cog config blocks and the `global` block, so you can
|
|
8
|
+
# configure cogs based on how the workflow was invoked.
|
|
9
|
+
chat do
|
|
10
|
+
# e.g., pick a cheaper model when the workflow is invoked with the `fast` flag:
|
|
11
|
+
# roast execute examples/targets_and_params.rb -- fast
|
|
12
|
+
model(arg?(:fast) ? "gpt-5.4-nano" : "gpt-5")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# `global` config applies to every cog; the same param accessors work here too.
|
|
16
|
+
global do
|
|
17
|
+
abort_on_failure! if arg?(:strict)
|
|
18
|
+
end
|
|
7
19
|
end
|
|
8
20
|
|
|
9
21
|
execute do
|
|
@@ -165,7 +165,8 @@ shortened names can be confusing. Use the complete module path.
|
|
|
165
165
|
```ruby
|
|
166
166
|
# Configure the cog to use the default provider when invoking an agent
|
|
167
167
|
#
|
|
168
|
-
# The default provider
|
|
168
|
+
# The default provider is the one named by the `ROAST_DEFAULT_AGENT_PROVIDER` environment variable,
|
|
169
|
+
# or Pi (`:pi`) when that variable is unset.
|
|
169
170
|
#: () -> void
|
|
170
171
|
def use_default_provider!
|
|
171
172
|
@values[:provider] = nil
|
|
@@ -386,7 +387,8 @@ end
|
|
|
386
387
|
# Configure the cog to use a specified provider when invoking an agent
|
|
387
388
|
#
|
|
388
389
|
# The provider is the source of the agent tool itself.
|
|
389
|
-
# If no provider is specified,
|
|
390
|
+
# If no provider is specified, Roast uses the provider named by the `ROAST_DEFAULT_AGENT_PROVIDER`
|
|
391
|
+
# environment variable, or Pi (`:pi`) when that variable is unset.
|
|
390
392
|
#
|
|
391
393
|
# A provider must be properly installed on your system in order for Roast to be able to use it.
|
|
392
394
|
#
|
|
@@ -519,7 +521,7 @@ Methods in `config_context.rbi` expose cog configuration interfaces and are the
|
|
|
519
521
|
#
|
|
520
522
|
# #### Configure the LLM provider
|
|
521
523
|
# - `provider(symbol)` - Set the agent provider (e.g., `:claude`)
|
|
522
|
-
# - `use_default_provider!` - Use the default provider (`:
|
|
524
|
+
# - `use_default_provider!` - Use the default provider (`:pi`, or `$ROAST_DEFAULT_AGENT_PROVIDER` when set)
|
|
523
525
|
#
|
|
524
526
|
# #### Configure the base command used to run the coding agent
|
|
525
527
|
# - `command(string_or_array)` - Set the base command for invoking the agent
|
|
@@ -70,7 +70,8 @@ These files provide the primary interface between users and Roast. The documenta
|
|
|
70
70
|
# Configure the cog to use a specified provider when invoking an agent
|
|
71
71
|
#
|
|
72
72
|
# The provider is the source of the agent tool itself.
|
|
73
|
-
# If no provider is specified,
|
|
73
|
+
# If no provider is specified, Roast uses the provider named by the `ROAST_DEFAULT_AGENT_PROVIDER`
|
|
74
|
+
# environment variable, or Pi (`:pi`) when that variable is unset.
|
|
74
75
|
#
|
|
75
76
|
# A provider must be properly installed on your system in order for Roast to be able to use it.
|
|
76
77
|
#
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
module Roast
|
|
5
5
|
# Context in which an individual cog block within the `execute` block of a workflow is evaluated
|
|
6
6
|
class CogInputManager
|
|
7
|
+
include WorkflowParamAccessors
|
|
8
|
+
|
|
7
9
|
class CogOutputAccessError < Roast::Error; end
|
|
8
10
|
|
|
9
11
|
class CogDoesNotExistError < CogOutputAccessError; end
|
|
@@ -104,50 +106,6 @@ module Roast
|
|
|
104
106
|
end
|
|
105
107
|
end
|
|
106
108
|
|
|
107
|
-
#: () -> String
|
|
108
|
-
def target!
|
|
109
|
-
raise ArgumentError, "expected exactly one target" unless @workflow_context.params.targets.length == 1
|
|
110
|
-
|
|
111
|
-
@workflow_context.params.targets.first #: as String
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
#: () -> Array[String]
|
|
115
|
-
def targets
|
|
116
|
-
@workflow_context.params.targets.dup
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
#: (Symbol) -> bool
|
|
120
|
-
def arg?(value)
|
|
121
|
-
@workflow_context.params.args.include?(value)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
#: () -> Array[Symbol]
|
|
125
|
-
def args
|
|
126
|
-
@workflow_context.params.args.dup
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
#: (Symbol) -> String?
|
|
130
|
-
def kwarg(key)
|
|
131
|
-
@workflow_context.params.kwargs[key]
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
#: (Symbol) -> String
|
|
135
|
-
def kwarg!(key)
|
|
136
|
-
raise ArgumentError, "expected keyword argument '#{key}' to be present" unless @workflow_context.params.kwargs.include?(key)
|
|
137
|
-
|
|
138
|
-
@workflow_context.params.kwargs[key] #: as String
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
#: (Symbol) -> bool
|
|
142
|
-
def kwarg?(key)
|
|
143
|
-
@workflow_context.params.kwargs.include?(key)
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
#: () -> Hash[Symbol, String]
|
|
147
|
-
def kwargs
|
|
148
|
-
@workflow_context.params.kwargs.dup
|
|
149
|
-
end
|
|
150
|
-
|
|
151
109
|
#: () -> Pathname
|
|
152
110
|
def tmpdir
|
|
153
111
|
Pathname.new(@workflow_context.tmpdir).realpath
|
|
@@ -5,12 +5,21 @@ module Roast
|
|
|
5
5
|
module Cogs
|
|
6
6
|
class Agent < Cog
|
|
7
7
|
class Config < Cog::Config
|
|
8
|
-
VALID_PROVIDERS = [:
|
|
8
|
+
VALID_PROVIDERS = [:pi, :claude].freeze #: Array[Symbol]
|
|
9
|
+
|
|
10
|
+
# Environment variable that overrides the built-in default agent provider.
|
|
11
|
+
#
|
|
12
|
+
# When an agent cog does not explicitly configure a provider, Roast uses the provider named by
|
|
13
|
+
# this variable, falling back to the built-in default (`VALID_PROVIDERS.first`, i.e. `:pi`) when it
|
|
14
|
+
# is unset or blank. The value is normalized (surrounding whitespace stripped, then downcased)
|
|
15
|
+
# before lookup, and an explicit `provider` configured on the cog always takes precedence over it.
|
|
16
|
+
DEFAULT_PROVIDER_ENV_VAR = "ROAST_DEFAULT_AGENT_PROVIDER" #: String
|
|
9
17
|
|
|
10
18
|
# Configure the cog to use a specified provider when invoking an agent
|
|
11
19
|
#
|
|
12
20
|
# The provider is the source of the agent tool itself.
|
|
13
|
-
# If no provider is specified,
|
|
21
|
+
# If no provider is specified, Roast uses the provider named by the `ROAST_DEFAULT_AGENT_PROVIDER`
|
|
22
|
+
# environment variable, or Pi (`:pi`) when that variable is unset.
|
|
14
23
|
#
|
|
15
24
|
# A provider must be properly installed on your system in order for Roast to be able to use it.
|
|
16
25
|
#
|
|
@@ -24,7 +33,8 @@ module Roast
|
|
|
24
33
|
|
|
25
34
|
# Configure the cog to use the default provider when invoking an agent
|
|
26
35
|
#
|
|
27
|
-
# The default provider
|
|
36
|
+
# The default provider is the one named by the `ROAST_DEFAULT_AGENT_PROVIDER` environment variable,
|
|
37
|
+
# or Pi (`:pi`) when that variable is unset.
|
|
28
38
|
#
|
|
29
39
|
# The provider must be properly installed on your system in order for Roast to be able to use it.
|
|
30
40
|
#
|
|
@@ -38,6 +48,10 @@ module Roast
|
|
|
38
48
|
|
|
39
49
|
# Get the validated provider name that the cog is configured to use when invoking an agent
|
|
40
50
|
#
|
|
51
|
+
# The provider is resolved in order of precedence: the provider explicitly configured on the cog,
|
|
52
|
+
# then the `ROAST_DEFAULT_AGENT_PROVIDER` environment variable (normalized by stripping surrounding
|
|
53
|
+
# whitespace and downcasing), then the built-in default (`VALID_PROVIDERS.first`, i.e. `:pi`).
|
|
54
|
+
#
|
|
41
55
|
# Note: this method will return the name of a valid provider or raise an `InvalidConfigError`.
|
|
42
56
|
# It will __not__, however, validate that the agent is properly installed on your system.
|
|
43
57
|
# If the agent is not properly installed, you will likely experience a failure when Roast attempts to
|
|
@@ -49,7 +63,8 @@ module Roast
|
|
|
49
63
|
#
|
|
50
64
|
#: () -> Symbol
|
|
51
65
|
def valid_provider!
|
|
52
|
-
|
|
66
|
+
env_default = ENV[DEFAULT_PROVIDER_ENV_VAR].presence&.strip&.downcase&.to_sym
|
|
67
|
+
provider = @values[:provider] || env_default || VALID_PROVIDERS.first
|
|
53
68
|
unless VALID_PROVIDERS.include?(provider)
|
|
54
69
|
raise InvalidConfigError, "'#{provider}' is not a valid provider. Available providers include: #{VALID_PROVIDERS.join(", ")}"
|
|
55
70
|
end
|
|
@@ -131,6 +146,47 @@ module Roast
|
|
|
131
146
|
@values[:model].presence
|
|
132
147
|
end
|
|
133
148
|
|
|
149
|
+
# Configure the cog to stop the agent if it runs longer than the given number of seconds
|
|
150
|
+
#
|
|
151
|
+
# When the limit is reached, the agent process is killed and the cog raises
|
|
152
|
+
# `Roast::CommandRunner::TimeoutError`. By default there is no timeout.
|
|
153
|
+
#
|
|
154
|
+
# #### See Also
|
|
155
|
+
# - `no_timeout!`
|
|
156
|
+
#
|
|
157
|
+
#: (Integer) -> void
|
|
158
|
+
def timeout(seconds)
|
|
159
|
+
@values[:timeout] = seconds
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Configure the cog to let the agent run for as long as it takes (the default)
|
|
163
|
+
#
|
|
164
|
+
# #### See Also
|
|
165
|
+
# - `timeout`
|
|
166
|
+
#
|
|
167
|
+
#: () -> void
|
|
168
|
+
def no_timeout!
|
|
169
|
+
@values[:timeout] = nil
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Get the validated number of seconds the agent may run before it is stopped
|
|
173
|
+
#
|
|
174
|
+
# Returns `nil` if the agent has no timeout. Raises an `InvalidConfigError` if the configured
|
|
175
|
+
# timeout is not positive.
|
|
176
|
+
#
|
|
177
|
+
# #### See Also
|
|
178
|
+
# - `timeout`
|
|
179
|
+
# - `no_timeout!`
|
|
180
|
+
#
|
|
181
|
+
#: () -> Integer?
|
|
182
|
+
def valid_timeout
|
|
183
|
+
seconds = @values[:timeout]
|
|
184
|
+
return if seconds.nil?
|
|
185
|
+
return seconds if seconds.positive?
|
|
186
|
+
|
|
187
|
+
raise InvalidConfigError, "timeout must be a positive number of seconds, got #{seconds.inspect}"
|
|
188
|
+
end
|
|
189
|
+
|
|
134
190
|
# Configure the cog with a custom system prompt that will completely replace the agent's
|
|
135
191
|
# default system prompt every time the agent is invoked
|
|
136
192
|
#
|
|
@@ -56,11 +56,14 @@ module Roast
|
|
|
56
56
|
#: (Agent::Config, String, String?, ?fork_session: bool) -> void
|
|
57
57
|
def initialize(config, prompt, session, fork_session: true)
|
|
58
58
|
@base_command = config.valid_command #: (String | Array[String])?
|
|
59
|
-
|
|
59
|
+
# The Claude CLI expects a bare model name, while Pi expects a fully-qualified
|
|
60
|
+
# `anthropic/<model>` id. Strip the prefix so the same model string works for either provider.
|
|
61
|
+
@model = config.valid_model&.delete_prefix("anthropic/") #: String?
|
|
60
62
|
@append_system_prompt = config.valid_append_system_prompt #: String?
|
|
61
63
|
@replace_system_prompt = config.valid_replace_system_prompt #: String?
|
|
62
64
|
@apply_permissions = config.apply_permissions? #: bool
|
|
63
65
|
@working_directory = config.valid_working_directory #: Pathname?
|
|
66
|
+
@timeout = config.valid_timeout #: Integer?
|
|
64
67
|
@context = Context.new #: Context
|
|
65
68
|
@result = Result.new #: Result
|
|
66
69
|
@raw_dump_file = config.valid_dump_raw_agent_messages_to_path #: Pathname?
|
|
@@ -82,6 +85,7 @@ module Roast
|
|
|
82
85
|
command_line,
|
|
83
86
|
working_directory: @working_directory,
|
|
84
87
|
stdin_content: @prompt,
|
|
88
|
+
timeout: @timeout,
|
|
85
89
|
stdout_handler: lambda { |line| handle_stdout(line) },
|
|
86
90
|
)
|
|
87
91
|
|