roast-ai 0.4.10 → 0.5.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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/docs/write-comments.md +36 -0
  3. data/.github/CODEOWNERS +1 -1
  4. data/.github/workflows/ci.yaml +10 -6
  5. data/.gitignore +0 -1
  6. data/.rubocop.yml +7 -1
  7. data/CLAUDE.md +2 -2
  8. data/CONTRIBUTING.md +2 -0
  9. data/Gemfile +19 -18
  10. data/Gemfile.lock +35 -58
  11. data/README.md +118 -1432
  12. data/README_LEGACY.md +1464 -0
  13. data/Rakefile +39 -4
  14. data/dev.yml +29 -0
  15. data/dsl/agent_sessions.rb +20 -0
  16. data/dsl/async_cogs.rb +49 -0
  17. data/dsl/async_cogs_complex.rb +67 -0
  18. data/dsl/call.rb +44 -0
  19. data/dsl/collect_from.rb +72 -0
  20. data/dsl/json_output.rb +28 -0
  21. data/dsl/map.rb +55 -0
  22. data/dsl/map_reduce.rb +37 -0
  23. data/dsl/map_with_index.rb +49 -0
  24. data/dsl/next_break.rb +40 -0
  25. data/dsl/next_break_parallel.rb +44 -0
  26. data/dsl/outputs.rb +39 -0
  27. data/dsl/outputs_bang.rb +36 -0
  28. data/dsl/parallel_map.rb +37 -0
  29. data/dsl/prompts/simple_prompt.md.erb +3 -0
  30. data/dsl/prototype.rb +5 -7
  31. data/dsl/repeat_loop_results.rb +53 -0
  32. data/dsl/ruby_cog.rb +72 -0
  33. data/dsl/simple_agent.rb +18 -0
  34. data/dsl/simple_chat.rb +15 -1
  35. data/dsl/simple_repeat.rb +29 -0
  36. data/dsl/skip.rb +36 -0
  37. data/dsl/step_communication.rb +2 -3
  38. data/dsl/targets_and_params.rb +57 -0
  39. data/dsl/temperature.rb +17 -0
  40. data/dsl/temporary_directory.rb +22 -0
  41. data/dsl/tutorial/01_your_first_workflow/README.md +179 -0
  42. data/dsl/tutorial/01_your_first_workflow/configured_chat.rb +33 -0
  43. data/dsl/tutorial/01_your_first_workflow/hello.rb +23 -0
  44. data/dsl/tutorial/02_chaining_cogs/README.md +310 -0
  45. data/dsl/tutorial/02_chaining_cogs/code_review.rb +104 -0
  46. data/dsl/tutorial/02_chaining_cogs/session_resumption.rb +92 -0
  47. data/dsl/tutorial/02_chaining_cogs/simple_chain.rb +84 -0
  48. data/dsl/tutorial/03_targets_and_params/README.md +230 -0
  49. data/dsl/tutorial/03_targets_and_params/multiple_targets.rb +65 -0
  50. data/dsl/tutorial/03_targets_and_params/single_target.rb +65 -0
  51. data/dsl/tutorial/04_configuration_options/README.md +209 -0
  52. data/dsl/tutorial/04_configuration_options/control_display_and_temperature.rb +104 -0
  53. data/dsl/tutorial/04_configuration_options/simple_config.rb +68 -0
  54. data/dsl/tutorial/05_control_flow/README.md +156 -0
  55. data/dsl/tutorial/05_control_flow/conditional_execution.rb +62 -0
  56. data/dsl/tutorial/05_control_flow/handling_failures.rb +77 -0
  57. data/dsl/tutorial/06_reusable_scopes/README.md +172 -0
  58. data/dsl/tutorial/06_reusable_scopes/accessing_scope_outputs.rb +126 -0
  59. data/dsl/tutorial/06_reusable_scopes/basic_scope.rb +63 -0
  60. data/dsl/tutorial/06_reusable_scopes/parameterized_scope.rb +78 -0
  61. data/dsl/tutorial/07_processing_collections/README.md +152 -0
  62. data/dsl/tutorial/07_processing_collections/basic_map.rb +70 -0
  63. data/dsl/tutorial/07_processing_collections/parallel_map.rb +74 -0
  64. data/dsl/tutorial/08_iterative_workflows/README.md +231 -0
  65. data/dsl/tutorial/08_iterative_workflows/basic_repeat.rb +57 -0
  66. data/dsl/tutorial/08_iterative_workflows/conditional_break.rb +57 -0
  67. data/dsl/tutorial/09_async_cogs/README.md +197 -0
  68. data/dsl/tutorial/09_async_cogs/basic_async.rb +38 -0
  69. data/dsl/tutorial/README.md +222 -0
  70. data/dsl/working_directory.rb +16 -0
  71. data/exe/roast +1 -1
  72. data/internal/documentation/architectural-notes.md +115 -0
  73. data/internal/documentation/doc-comments-external.md +686 -0
  74. data/internal/documentation/doc-comments-internal.md +342 -0
  75. data/internal/documentation/doc-comments.md +211 -0
  76. data/lib/roast/dsl/cog/config.rb +274 -3
  77. data/lib/roast/dsl/cog/input.rb +53 -10
  78. data/lib/roast/dsl/cog/output.rb +297 -8
  79. data/lib/roast/dsl/cog/registry.rb +35 -3
  80. data/lib/roast/dsl/cog/stack.rb +1 -1
  81. data/lib/roast/dsl/cog/store.rb +5 -5
  82. data/lib/roast/dsl/cog.rb +70 -14
  83. data/lib/roast/dsl/cog_input_context.rb +36 -1
  84. data/lib/roast/dsl/cog_input_manager.rb +116 -7
  85. data/lib/roast/dsl/cogs/agent/config.rb +465 -0
  86. data/lib/roast/dsl/cogs/agent/input.rb +81 -0
  87. data/lib/roast/dsl/cogs/agent/output.rb +59 -0
  88. data/lib/roast/dsl/cogs/agent/provider.rb +51 -0
  89. data/lib/roast/dsl/cogs/agent/providers/claude/claude_invocation.rb +185 -0
  90. data/lib/roast/dsl/cogs/agent/providers/claude/message.rb +73 -0
  91. data/lib/roast/dsl/cogs/agent/providers/claude/messages/assistant_message.rb +36 -0
  92. data/lib/roast/dsl/cogs/agent/providers/claude/messages/result_message.rb +61 -0
  93. data/lib/roast/dsl/cogs/agent/providers/claude/messages/system_message.rb +47 -0
  94. data/lib/roast/dsl/cogs/agent/providers/claude/messages/text_message.rb +36 -0
  95. data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_result_message.rb +47 -0
  96. data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_use_message.rb +46 -0
  97. data/lib/roast/dsl/cogs/agent/providers/claude/messages/unknown_message.rb +27 -0
  98. data/lib/roast/dsl/cogs/agent/providers/claude/messages/user_message.rb +37 -0
  99. data/lib/roast/dsl/cogs/agent/providers/claude/tool_result.rb +51 -0
  100. data/lib/roast/dsl/cogs/agent/providers/claude/tool_use.rb +48 -0
  101. data/lib/roast/dsl/cogs/agent/providers/claude.rb +31 -0
  102. data/lib/roast/dsl/cogs/agent/stats.rb +92 -0
  103. data/lib/roast/dsl/cogs/agent/usage.rb +62 -0
  104. data/lib/roast/dsl/cogs/agent.rb +75 -0
  105. data/lib/roast/dsl/cogs/chat/config.rb +453 -0
  106. data/lib/roast/dsl/cogs/chat/input.rb +92 -0
  107. data/lib/roast/dsl/cogs/chat/output.rb +64 -0
  108. data/lib/roast/dsl/cogs/chat/session.rb +68 -0
  109. data/lib/roast/dsl/cogs/chat.rb +59 -56
  110. data/lib/roast/dsl/cogs/cmd.rb +248 -61
  111. data/lib/roast/dsl/cogs/ruby.rb +171 -0
  112. data/lib/roast/dsl/command_runner.rb +191 -0
  113. data/lib/roast/dsl/config_manager.rb +58 -11
  114. data/lib/roast/dsl/control_flow.rb +41 -0
  115. data/lib/roast/dsl/execution_manager.rb +162 -32
  116. data/lib/roast/dsl/nil_assertions.rb +23 -0
  117. data/lib/roast/dsl/system_cog/params.rb +32 -0
  118. data/lib/roast/dsl/system_cog.rb +36 -0
  119. data/lib/roast/dsl/system_cogs/call.rb +162 -0
  120. data/lib/roast/dsl/system_cogs/map.rb +448 -0
  121. data/lib/roast/dsl/system_cogs/repeat.rb +242 -0
  122. data/lib/roast/dsl/workflow.rb +26 -16
  123. data/lib/roast/dsl/workflow_context.rb +20 -0
  124. data/lib/roast/dsl/workflow_params.rb +24 -0
  125. data/lib/roast/sorbet_runtime_stub.rb +154 -0
  126. data/lib/roast/tools/apply_diff.rb +1 -3
  127. data/lib/roast/tools/cmd.rb +4 -3
  128. data/lib/roast/tools/read_file.rb +1 -1
  129. data/lib/roast/tools/update_files.rb +1 -1
  130. data/lib/roast/tools/write_file.rb +1 -1
  131. data/lib/roast/version.rb +1 -1
  132. data/lib/roast/workflow/base_workflow.rb +4 -0
  133. data/lib/roast/workflow/step_loader.rb +14 -2
  134. data/lib/roast-ai.rb +4 -0
  135. data/lib/roast.rb +58 -21
  136. data/{roast.gemspec → roast-ai.gemspec} +9 -13
  137. data/sorbet/rbi/gems/async@2.34.0.rbi +1577 -0
  138. data/sorbet/rbi/gems/cli-kit@5.2.0.rbi +2063 -0
  139. data/sorbet/rbi/gems/{cli-ui@2.3.0.rbi → cli-ui@2.7.0-6bdefd1d06305e5d6ae312ac76f9c88f88658dda.rbi} +1418 -1013
  140. data/sorbet/rbi/gems/console@1.34.2.rbi +1193 -0
  141. data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +50 -0
  142. data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +35 -0
  143. data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +41 -0
  144. data/sorbet/rbi/gems/io-event@1.14.0.rbi +724 -0
  145. data/sorbet/rbi/gems/metrics@0.15.0.rbi +9 -0
  146. data/sorbet/rbi/gems/traces@0.18.2.rbi +9 -0
  147. data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +1185 -5
  148. data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +311 -5
  149. data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +486 -5
  150. data/sorbet/tapioca/config.yml +6 -0
  151. data/sorbet/tapioca/require.rb +2 -0
  152. metadata +157 -30
  153. data/dsl/less_simple.rb +0 -112
  154. data/dsl/scoped_executors.rb +0 -28
  155. data/dsl/simple.rb +0 -8
  156. data/lib/roast/dsl/cogs/execute.rb +0 -46
  157. data/lib/roast/dsl/cogs/graph.rb +0 -53
  158. data/sorbet/rbi/gems/cgi@0.5.0.rbi +0 -2961
  159. data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +0 -568
  160. data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +0 -1991
  161. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +0 -672
  162. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +0 -1894
  163. data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +0 -659
  164. data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +0 -781
  165. data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +0 -1127
  166. data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +0 -3727
  167. data/sorbet/rbi/gems/dry-types@1.8.3.rbi +0 -3969
  168. data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +0 -1588
  169. data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +0 -136
  170. data/sorbet/rbi/gems/mime-types@3.7.0.rbi +0 -1342
  171. data/sorbet/rbi/gems/rack@2.2.19.rbi +0 -5676
  172. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +0 -435
  173. data/sorbet/rbi/gems/yard@0.9.37.rbi +0 -18492
@@ -0,0 +1,310 @@
1
+ # Chapter 2: Chaining Cogs Together
2
+
3
+ In the previous chapter, you learned how to use a single chat cog. Now you'll learn how to chain multiple cogs together,
4
+ where the output of one step becomes the input to the next. This is where workflows become truly powerful.
5
+
6
+ ## What You'll Learn
7
+
8
+ - How to name cogs so you can reference them
9
+ - How to access outputs from previous cogs
10
+ - How to chain cogs together to build multi-step workflows
11
+ - The difference between `agent` and `chat` cogs
12
+ - How to use the `ruby` cog for custom logic
13
+
14
+ ## Naming Cogs
15
+
16
+ When you have multiple steps, you need to name them so you can reference their outputs. Give each cog a descriptive name
17
+ using a symbol:
18
+
19
+ ```ruby
20
+ execute do
21
+ chat(:analyze) { "Analyze this text..." }
22
+ chat(:summarize) { "Summarize that analysis..." }
23
+ end
24
+ ```
25
+
26
+ The name goes in parentheses after the cog type.
27
+
28
+ ## Accessing Outputs
29
+
30
+ To access the output from a previous cog, reference it by name just like you defined it:
31
+
32
+ ```ruby
33
+ execute do
34
+ chat(:analyze) { "Analyze this: #{data}" }
35
+
36
+ # Access the 'analyze' cog's output
37
+ chat(:summarize) do
38
+ analysis = chat(:analyze).response
39
+ "Summarize this analysis: #{analysis}"
40
+ end
41
+ end
42
+ ```
43
+
44
+ This returns the cog's output, or `nil` if the cog didn't run (we'll learn about conditionally skipping steps in a later
45
+ lesson.
46
+
47
+ ### Different Output Methods
48
+
49
+ Different cog types provide different types of output. Here are few highlights:
50
+
51
+ - `chat(:name).response` - The text response from a chat cog
52
+ - `agent(:name).response` - The text response from an agent cog
53
+ - `ruby(:name).value` - The return value from a ruby cog
54
+ - `cmd(:name).out` - The stdout from a command cog
55
+ - `cmd(:name).err` - The stderr from a command cog
56
+
57
+ Check out the documentation for each cog to see the other output values it can provide.
58
+
59
+ ### Text Output
60
+
61
+ All cogs that produce textual output (`agent`, `chat`, and `cmd`) include some standard convenience methods to make
62
+ working with that output easy:
63
+
64
+ - `.text` - The output text with surrounding whitespace removed.
65
+ Using `cmd(:name).text` is particularly useful in place of `cmd(:name).out`
66
+ when you're expecting a single line of output and just want that value without
67
+ a trailing newline.
68
+ - `.lines` - An array containing the individual lines of the output text, each with
69
+ surrounding whitespace removed. `chat(:name).lines` is equivalent to
70
+ `chat(:name).response.lines.map(&:strip)`
71
+ - `.json` - A hash parsed from the output text in JSON format, or `nil` if the text could not
72
+ be parsed as valid JSON. `.json!` is equivalent, but will raise an exception if the
73
+ parsing fails.
74
+
75
+ ### Checking If a Cog Ran
76
+
77
+ Use the `?` suffix to check whether a cog ran:
78
+
79
+ ```ruby
80
+ execute do
81
+ chat do |my|
82
+ result = if chat?(:optional_step)
83
+ # It ran, safe to access
84
+ chat(:optional_step).response
85
+ else
86
+ # It didn't run (maybe it was skipped)
87
+ "No analysis available"
88
+ end
89
+ my.prompt = "Characterize this result: #{result}"
90
+ end
91
+ end
92
+ ```
93
+
94
+ ### The `!` Suffix: Convenient Shorthand
95
+
96
+ When you're not intentionally skipping cogs, use the `!` suffix for convenient shorthand:
97
+
98
+ ```ruby
99
+ execute do
100
+ chat(:analyze) { "Analyze this: #{data}" }
101
+
102
+ chat(:summarize) do
103
+ analysis = chat!(:analyze).response # Raises error if analyze didn't run
104
+ "Summarize this analysis: #{analysis}"
105
+ end
106
+ end
107
+ ```
108
+
109
+ The `!` suffix means "get this cog's output, and raise an error if it didn't run." This catches mistakes early. If you
110
+ try to access a cog that was accidentally skipped, or failed, you'll get a clear error right away, instead of a `nil`
111
+ result and a potential `NoMethodError` later on.
112
+
113
+ ## The Agent Cog
114
+
115
+ The `agent` cog is similar to `chat`, but it runs locally and has access to your filesystem and the ability to use
116
+ a suite of local tools. Use `agent` when you need to read files, search code, or interact with your local environment:
117
+
118
+ ```ruby
119
+ execute do
120
+ agent(:code_review) do
121
+ <<~PROMPT
122
+ Read the Ruby files in the src/ directory and identify
123
+ any potential security issues. Focus on input validation
124
+ and data sanitization.
125
+ PROMPT
126
+ end
127
+ end
128
+ ```
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.
132
+
133
+ ### When to Use Agent vs Chat
134
+
135
+ - **Use `agent`** when you need to:
136
+ - Read or write local files
137
+ - Search through code
138
+ - Run shell commands
139
+ - Interact with your development environment
140
+
141
+ - **Use `chat`** when you need to:
142
+ - Process data already in memory
143
+ - Perform reasoning without file access
144
+ - Generate text or analysis from provided context
145
+ - Use less expensive/faster models for simple tasks
146
+
147
+ Both are equally capable of complex reasoning. The difference is **access**, not intelligence.
148
+
149
+ ## The Ruby Cog
150
+
151
+ The `ruby` cog lets you run custom Ruby code within your workflow. Use it for data processing, formatting, or any logic
152
+ that doesn't need an LLM:
153
+
154
+ ```ruby
155
+ execute do
156
+ chat(:analyze) { "Analyze this data..." }
157
+
158
+ ruby(:format_output) do
159
+ analysis = chat!(:analyze).response
160
+
161
+ # Custom formatting logic
162
+ formatted = "=" * 60 + "\n"
163
+ formatted += "ANALYSIS RESULTS\n"
164
+ formatted += "=" * 60 + "\n"
165
+ formatted += analysis + "\n"
166
+ formatted += "=" * 60
167
+
168
+ puts formatted
169
+
170
+ # The return value is stored for later usage by other cogs
171
+ { status: "complete", length: analysis.length }
172
+ end
173
+ end
174
+ ```
175
+
176
+ The ruby cog's return value is accessible via `ruby!(:name).value`.
177
+
178
+ ## Data Flow Example
179
+
180
+ Here's how data flows through a typical workflow:
181
+
182
+ ```ruby
183
+ execute do
184
+ # Step 1: Select some files
185
+ cmd(:recent_files_changes) do
186
+ "git show --name-only HEAD~3..HEAD"
187
+ end
188
+
189
+ # Step 2: Agent analyzes the code
190
+ agent(:security_review) do
191
+ <<~PROMPT
192
+ Review these recently changed files for security vulnerabilities:
193
+
194
+ #{cmd!(:recent_files_changes).text}
195
+
196
+ Identify specific issues and explain the risk.
197
+ PROMPT
198
+ end
199
+
200
+ # Step 3: Chat creates a simple summary
201
+ chat(:simple_summary) do
202
+ review = agent!(:security_review).response
203
+ <<~PROMPT
204
+ Summarize this security review in 2-3 sentences that
205
+ a non-technical manager would understand:
206
+
207
+ #{review}
208
+ PROMPT
209
+ end
210
+
211
+ # Step 4: Ruby formats the final output
212
+ ruby(:display) do
213
+ puts "\n" + "=" * 60
214
+ puts "EXECUTIVE SUMMARY"
215
+ puts "-" * 60
216
+ puts chat!(:simple_summary).response
217
+ puts "=" * 60 + "\n"
218
+ puts "SECURITY REVIEW"
219
+ puts "=" * 60
220
+ puts agent!(:security_review).response
221
+ puts "\n" + "-" * 60
222
+ end
223
+ end
224
+ ```
225
+
226
+ Data flows: **shell command → agent analysis → chat summary → ruby formatting**
227
+
228
+ ## Resuming Conversations
229
+
230
+ Both `chat` and `agent` cogs can resume previous conversations by passing their session to a subsequent cog. This allows
231
+ multi-turn conversations where the LLM remembers context from earlier exchanges:
232
+
233
+ ```ruby
234
+ execute do
235
+ # First turn - tell the LLM something
236
+ chat(:introduce_topic) do
237
+ "The secret code word is 'thunderbolt'. Remember it."
238
+ end
239
+
240
+ # Second turn - resume the session and ask about it
241
+ chat(:recall_code) do |my|
242
+ my.session = chat!(:introduce_topic).session
243
+ my.prompt = "What was the secret code word?"
244
+ end
245
+ end
246
+ ```
247
+
248
+ The same pattern works with `agent` cogs:
249
+
250
+ ```ruby
251
+ execute do
252
+ agent(:analyze) { "List files in this directory" }
253
+
254
+ agent(:followup) do |my|
255
+ my.session = agent!(:analyze).session
256
+ my.prompt = "Tell me more about one of those files"
257
+ end
258
+ end
259
+ ```
260
+
261
+ **Important:** You cannot resume an agent's session in a chat cog, or vice versa. They are not interchangeable.
262
+
263
+ ## Running the Workflows
264
+
265
+ To run the examples in this chapter:
266
+
267
+ ```bash
268
+ # Simple chaining example
269
+ bin/roast execute --executor=dsl dsl/tutorial/02_chaining_cogs/simple_chain.rb
270
+ ```
271
+
272
+ ```bash
273
+ # Realistic code review workflow
274
+ bin/roast execute --executor=dsl dsl/tutorial/02_chaining_cogs/code_review.rb
275
+ ```
276
+
277
+ ```bash
278
+ # Session resumption with multi-turn conversations
279
+ bin/roast execute --executor=dsl dsl/tutorial/02_chaining_cogs/session_resumption.rb
280
+ ```
281
+
282
+ ## Try It Yourself
283
+
284
+ 1. **Run both workflows** and observe how data flows between steps
285
+ 2. **Modify the prompts** - Change what the agent looks for or how the chat summarizes
286
+ 3. **Add a new step** - Try adding another chat step that processes the summary differently
287
+ 4. **Change the order** - What happens if you try to access a cog before it runs?
288
+ 5. **Try the `!` suffix** - Replace `chat(:analyze)` with `chat!(:analyze)` and see the difference
289
+
290
+ ## Key Takeaways
291
+
292
+ - Name cogs with descriptive symbols: `chat(:analyze)`
293
+ - Access outputs by referencing the cog: `chat(:analyze).response`
294
+ - Use `?` to check if a cog ran: `chat?(:analyze)`
295
+ - Use `!` for convenient shorthand that raises an error right away if the cog didn't run
296
+ - Different cogs have different output methods: `.response`, `.value`, `.out`
297
+ - Many cogs have common convenience methods: `.text`, `.lines`, `.json!`
298
+ - Use `agent` for filesystem access, `chat` for pure reasoning
299
+ - Use `ruby` for custom logic and formatting
300
+ - Data flows through your workflow in the order you define steps
301
+ - Reference any past steps' output in a current step's input
302
+ - Resume conversations by passing `.session` to subsequent cogs with `my.session = ...`
303
+ - Cannot mix chat and agent sessions - they are different types
304
+
305
+ ## What's Next?
306
+
307
+ In the next chapter, you'll learn how to make workflows more flexible by accepting targets and custom parameters
308
+ from the command line, so you can reuse the same workflow with different inputs.
309
+
310
+ But first, make sure you understand how outputs flow between cogs. This is the foundation of all workflows!
@@ -0,0 +1,104 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ # This workflow demonstrates using agent and chat cogs together.
7
+ # Agent reads/analyzes code, chat summarizes findings, ruby formats output.
8
+
9
+ config do
10
+ agent do
11
+ model "claude-3-5-haiku-20241022"
12
+ provider :claude
13
+ end
14
+
15
+ chat do
16
+ model "gpt-4o-mini"
17
+ provider :openai
18
+ end
19
+ end
20
+
21
+ execute do
22
+ # Step 1: Agent performs detailed security review
23
+ # The agent has access to file system and tools, though we're providing code directly here
24
+ agent(:review_security) do
25
+ <<~PROMPT
26
+ You are a security-focused code reviewer. Analyze the files changed by the latest commit in this project
27
+ and identify security vulnerabilities.
28
+
29
+ For each issue found, explain:
30
+ 1. What the vulnerability is
31
+ 2. Why it's dangerous
32
+ 3. How to fix it
33
+ PROMPT
34
+ end
35
+
36
+ # Step 2: Chat creates a prioritized summary
37
+ # (There's no reason you couldn't use the `agent` to generate a summary;
38
+ # we're just using `chat` here for illustration purposes.)
39
+ chat(:prioritize) do
40
+ review = agent!(:review_security).text
41
+ <<~PROMPT
42
+ Review this security analysis and create a prioritized action list.
43
+ Rank issues by severity (Critical, High, Medium, Low).
44
+
45
+ Security Review:
46
+ #{review}
47
+
48
+ Format as:
49
+ - **[Severity]** Issue: Brief description
50
+ PROMPT
51
+ end
52
+
53
+ # Step 3: Chat creates an executive summary
54
+ chat(:summarize_for_executive) do
55
+ review = agent!(:review_security).response
56
+ <<~PROMPT
57
+ Create a 2-3 sentence executive summary of this security review
58
+ for a non-technical stakeholder:
59
+
60
+ #{review}
61
+
62
+ Focus on business impact and urgency.
63
+ PROMPT
64
+ end
65
+
66
+ # Step 4: Ruby formats and displays the complete report
67
+ ruby(:display_report) do
68
+ puts "\n" + "=" * 80
69
+ puts "CODE SECURITY REVIEW REPORT"
70
+ puts "=" * 80
71
+
72
+ puts "\nEXECUTIVE SUMMARY"
73
+ puts "-" * 80
74
+ puts chat!(:summarize_for_executive).response
75
+
76
+ puts "\n\nPRIORITIZED ACTION ITEMS"
77
+ puts "-" * 80
78
+ puts chat!(:prioritize).response
79
+
80
+ puts "\n\nDETAILED FINDINGS"
81
+ puts "-" * 80
82
+ puts agent!(:review_security).response
83
+
84
+ puts "\n" + "=" * 80 + "\n"
85
+
86
+ # Return structured data
87
+ {
88
+ report_generated_at: Time.now.iso8601,
89
+ sections: ["executive_summary", "priority_summary", "detailed_findings"],
90
+ total_length: agent!(:review_security).response.length,
91
+ }
92
+ end
93
+
94
+ # Optional: Use the ruby cog's return value
95
+ ruby(:check_report) do
96
+ report_data = ruby!(:display_report).value
97
+
98
+ if report_data[:total_length] > 0
99
+ puts "✓ Report generated successfully at #{report_data[:report_generated_at]}"
100
+ else
101
+ puts "⚠ Warning: Report appears to be empty"
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,92 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ config do
7
+ chat do
8
+ model "gpt-4o-mini"
9
+ no_display!
10
+ show_stats!
11
+ end
12
+ chat(:recall_code) do
13
+ model "gpt-4.1-nano"
14
+ end
15
+ agent do
16
+ model "haiku"
17
+ no_display!
18
+ show_stats!
19
+ end
20
+ agent(:followup_question) do
21
+ model "sonnet"
22
+ end
23
+ end
24
+
25
+ execute do
26
+ # First conversation turn - tell the LLM something
27
+ chat(:introduce_topic) do
28
+ <<~PROMPT
29
+ I'm going to tell you a secret code word. Remember it for later.
30
+ The secret code word is: "thunderbolt"
31
+
32
+ Just respond with "OK, I'll remember that."
33
+ PROMPT
34
+ end
35
+
36
+ ruby do
37
+ puts "First turn: #{chat!(:introduce_topic).text}"
38
+ end
39
+
40
+ # Second turn - resume the session and ask about it
41
+ chat(:recall_code) do |my|
42
+ # Resume the previous conversation by passing the session
43
+ # You can even resume with a different model that you used earlier in the session
44
+ my.session = chat!(:introduce_topic).session
45
+ my.prompt = "What was the secret code word I told you?"
46
+ end
47
+
48
+ ruby do
49
+ puts "Second turn: #{chat!(:recall_code).text}"
50
+ end
51
+
52
+ # Third turn - continue the conversation further
53
+ chat(:update_code) do |my|
54
+ # Can resume from any previous step in the conversation chain
55
+ my.session = chat!(:recall_code).session
56
+ my.prompt = "The new code word is 'mermaid'"
57
+ end
58
+
59
+ # Fourth turn - resume from an earlier point
60
+ chat(:resume_from_beginning) do |my|
61
+ # Every time you resume from a particular previous session, a new session is forked.
62
+ # You can always resume from that point again, without any new context being present.
63
+ my.session = chat!(:introduce_topic).session
64
+ my.prompt = "What is the current secret code word?"
65
+ end
66
+
67
+ ruby do
68
+ puts "Third turn: #{chat!(:update_code).response}"
69
+ # This will be the original word from the first turn
70
+ puts "Fourth turn: #{chat!(:resume_from_beginning).response}"
71
+ end
72
+
73
+ # Example with agent cog - works the same way
74
+ agent(:analyze_file) do
75
+ "What files are in the current directory? Just list a few."
76
+ end
77
+
78
+ ruby do
79
+ puts "\n--- Agent Session ---"
80
+ puts "Agent response: #{agent!(:analyze_file).response}"
81
+ end
82
+
83
+ agent(:followup_question) do |my|
84
+ # Resume the agent session
85
+ my.session = agent!(:analyze_file).session
86
+ "Pick one of those files and tell me what it is."
87
+ end
88
+
89
+ ruby do
90
+ puts "Agent followup: #{agent!(:followup_question).response}"
91
+ end
92
+ end
@@ -0,0 +1,84 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Workflow
5
+
6
+ # This workflow demonstrates basic chaining of cogs.
7
+ # Data flows: sample text → analysis → summary → formatted output
8
+
9
+ config do
10
+ chat do
11
+ model "gpt-4o-mini"
12
+ provider :openai
13
+ end
14
+ end
15
+
16
+ execute do
17
+ # Sample data embedded in the workflow
18
+ customer_feedback = <<~TEXT
19
+ I've been using your product for 3 months now. The interface is
20
+ really intuitive and I love the dark mode. However, the mobile
21
+ app crashes frequently when I try to upload photos. Also, the
22
+ export feature could be faster... it takes forever to download
23
+ large files! Overall though, I'm happy with the purchase and
24
+ would recommend it to friends.
25
+ TEXT
26
+
27
+ # Step 1: Analyze the feedback
28
+ chat(:analyze) do
29
+ <<~PROMPT
30
+ Analyze this customer feedback and identify:
31
+ 1. Positive points
32
+ 2. Issues/problems
33
+ 3. Feature requests
34
+
35
+ Feedback:
36
+ #{customer_feedback}
37
+
38
+ Provide a structured analysis.
39
+ PROMPT
40
+ end
41
+
42
+ # Step 2: Create a concise summary
43
+ # Note how we access the previous cog's output
44
+ chat(:summarize) do
45
+ analysis = chat!(:analyze).response
46
+
47
+ <<~PROMPT
48
+ Take this feedback analysis and create a 2-3 sentence
49
+ summary suitable for a product team standup:
50
+
51
+ #{analysis}
52
+
53
+ Focus on actionable items.
54
+ PROMPT
55
+ end
56
+
57
+ # Step 3: Format and display the results
58
+ ruby(:display) do
59
+ puts "\n" + "=" * 70
60
+ puts "CUSTOMER FEEDBACK ANALYSIS"
61
+ puts "=" * 70
62
+
63
+ puts "\nORIGINAL FEEDBACK:"
64
+ puts "-" * 70
65
+ puts customer_feedback
66
+
67
+ puts "\nEXECUTIVE SUMMARY:"
68
+ puts "-" * 70
69
+ puts chat!(:summarize).text
70
+
71
+ puts "\nDETAILED ANALYSIS:"
72
+ puts "-" * 70
73
+ puts chat!(:analyze).text
74
+
75
+ puts "=" * 70 + "\n"
76
+
77
+ # Return a value that could be used by subsequent steps
78
+ {
79
+ status: "complete",
80
+ feedback_length: customer_feedback.length,
81
+ summary_lines: chat!(:summarize).lines.length,
82
+ }
83
+ end
84
+ end