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,31 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ module Cogs
7
+ class Agent < Cog
8
+ module Providers
9
+ class Claude < Provider
10
+ class Output < Agent::Output
11
+ delegate :response, :session, :stats, to: :@invocation_result
12
+
13
+ #: (ClaudeInvocation::Result) -> void
14
+ def initialize(invocation_result)
15
+ super()
16
+ @invocation_result = invocation_result
17
+ end
18
+ end
19
+
20
+ #: (Agent::Input) -> Agent::Output
21
+ def invoke(input)
22
+ invocation = ClaudeInvocation.new(@config, input)
23
+ invocation.run!
24
+ Output.new(invocation.result)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,92 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ module Cogs
7
+ class Agent < Cog
8
+ # Statistics about agent execution
9
+ #
10
+ # Contains metrics tracking the performance and resource usage of an agent execution,
11
+ # including duration, conversation turns, token usage, and cost. Statistics are broken
12
+ # down by model when multiple models are used during execution.
13
+ class Stats
14
+ include ActiveSupport::NumberHelper
15
+
16
+ NO_VALUE = "---"
17
+
18
+ # The total execution duration in milliseconds
19
+ #
20
+ # Measures the wall-clock time from when the agent started executing until it completed.
21
+ # This includes all time spent on API calls, processing, and waiting.
22
+ #
23
+ #: Integer?
24
+ attr_accessor :duration_ms
25
+
26
+ # The number of conversation turns in the agent execution
27
+ #
28
+ # A turn represents one complete back-and-forth exchange between the user (or system)
29
+ # and the agent. For example, if the user sends a prompt and the agent responds, that
30
+ # is one turn. If the agent then uses a tool and responds again, that is another turn.
31
+ #
32
+ #: Integer?
33
+ attr_accessor :num_turns
34
+
35
+ # Aggregate token usage and cost across all models
36
+ #
37
+ # Provides the total input tokens, output tokens, and cost in USD for the entire
38
+ # agent execution, regardless of which models were used.
39
+ #
40
+ # #### See Also
41
+ # - `model_usage` - for per-model usage breakdown
42
+ # - `Agent::Usage`
43
+ #
44
+ #: Usage
45
+ attr_accessor :usage
46
+
47
+ # Token usage and cost broken down by model
48
+ #
49
+ # A hash mapping model names (as strings) to their individual usage statistics.
50
+ # This allows tracking how much each model contributed to the overall resource usage
51
+ # when multiple models were used during execution.
52
+ #
53
+ # #### See Also
54
+ # - `usage` - for aggregate usage across all models
55
+ # - `Agent::Usage`
56
+ #
57
+ #: Hash[String, Usage]
58
+ attr_accessor :model_usage
59
+
60
+ def initialize
61
+ @usage = Usage.new
62
+ @model_usage = {}
63
+ end
64
+
65
+ # Get a human-readable string representation of the statistics
66
+ #
67
+ # Formats the statistics into a multi-line string with the following information:
68
+ # - Number of turns
69
+ # - Total duration (formatted as a human-readable duration)
70
+ # - Total cost in USD (formatted with 6 decimal places)
71
+ # - Per-model token usage (input and output tokens)
72
+ #
73
+ # Values that are not available are shown as "---".
74
+ #
75
+ #: () -> String
76
+ def to_s
77
+ lines = []
78
+ lines << "Turns: #{num_turns.nil? ? NO_VALUE : number_to_human(num_turns)}"
79
+ lines << "Duration: #{duration_ms.nil? ? NO_VALUE : ActiveSupport::Duration.build((duration_ms || 0) / 1000).inspect}"
80
+ lines << "Cost (USD): $#{usage.cost_usd.nil? ? NO_VALUE : number_to_human(usage.cost_usd, precision: 6, significant: false)}"
81
+ model_usage.each do |m, u|
82
+ input_tokens = u.input_tokens.nil? ? NO_VALUE : number_to_human(u.input_tokens)
83
+ output_tokens = u.output_tokens.nil? ? NO_VALUE : number_to_human(u.output_tokens)
84
+ lines << "Tokens (#{m}): #{input_tokens} in, #{output_tokens} out"
85
+ end
86
+ lines.join("\n")
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,62 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ module Cogs
7
+ class Agent < Cog
8
+ # Token usage and cost information for agent execution
9
+ #
10
+ # Tracks the number of input and output tokens consumed during agent execution,
11
+ # along with the associated cost in USD. This information is used to monitor
12
+ # resource consumption and estimate execution costs.
13
+ #
14
+ # Usage data can represent either aggregate usage across all models or usage
15
+ # for a specific model when tracked in the per-model breakdown.
16
+ #
17
+ # #### See Also
18
+ # - `Agent::Stats` - contains aggregate and per-model usage information
19
+ class Usage
20
+ # The number of input tokens consumed
21
+ #
22
+ # Input tokens represent the text sent to the agent, including the user prompt,
23
+ # system instructions, conversation history, and any other context provided to
24
+ # the model. This metric is used to calculate the cost of providing input to the agent.
25
+ #
26
+ # #### See Also
27
+ # - `output_tokens`
28
+ # - `cost_usd`
29
+ #
30
+ #: Integer?
31
+ attr_accessor :input_tokens
32
+
33
+ # The number of output tokens generated
34
+ #
35
+ # Output tokens represent the text generated by the agent in response to the input.
36
+ # This includes the agent's responses, reasoning, and any other text produced during
37
+ # execution. This metric is used to calculate the cost of the agent's output.
38
+ #
39
+ # #### See Also
40
+ # - `input_tokens`
41
+ # - `cost_usd`
42
+ #
43
+ #: Integer?
44
+ attr_accessor :output_tokens
45
+
46
+ # The total cost in United States Dollars (USD)
47
+ #
48
+ # Represents the monetary cost of the agent execution based on the provider's pricing
49
+ # model. This typically accounts for both input and output token usage, though pricing
50
+ # models may vary by provider and model.
51
+ #
52
+ # #### See Also
53
+ # - `input_tokens`
54
+ # - `output_tokens`
55
+ #
56
+ #: Float?
57
+ attr_accessor :cost_usd
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,75 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ module Cogs
7
+ # Agent cog for running coding agents on the local machine
8
+ #
9
+ # The agent cog runs a coding agent on the local machine with access to local files,
10
+ # tools, and MCP servers. It is designed for coding tasks and any work requiring local
11
+ # filesystem access.
12
+ #
13
+ # Key capabilities:
14
+ # - Access to local filesystem (read and write files)
15
+ # - Can run local tools and commands
16
+ # - Access to locally-configured MCP servers
17
+ # - Maintain session state across multiple invocations
18
+ # - Resume previous conversations using session identifiers
19
+ # - Track detailed execution statistics including token usage and cost
20
+ #
21
+ # For pure LLM interaction without local system access, use the `chat` cog instead.
22
+ class Agent < Cog
23
+ # Parent class for all agent cog errors
24
+ class AgentCogError < Roast::Error; end
25
+
26
+ # Raised when an unknown or unsupported provider is specified
27
+ class UnknownProviderError < AgentCogError; end
28
+
29
+ # Raised when a required provider is not configured
30
+ class MissingProviderError < AgentCogError; end
31
+
32
+ # Raised when a required prompt is not provided
33
+ class MissingPromptError < AgentCogError; end
34
+
35
+ # The configuration object for this agent cog instance
36
+ #
37
+ #: Agent::Config
38
+ attr_reader :config
39
+
40
+ # Execute the agent with the given input and return the output
41
+ #
42
+ # Invokes the configured agent provider with the input prompt and any session context.
43
+ # Optionally displays the user prompt, agent response, and execution statistics to the
44
+ # console based on the cog's configuration.
45
+ #
46
+ # The agent may make multiple turns (back-and-forth exchanges) during execution,
47
+ # especially when using tools. Each turn is counted in the execution statistics.
48
+ #
49
+ #: (Input) -> Output
50
+ def execute(input)
51
+ puts "[USER PROMPT] #{input.valid_prompt!}" if config.show_prompt?
52
+ output = provider.invoke(input)
53
+ # NOTE: If progress is displayed, the agent's response will always be the last progress message,
54
+ # so showing it again is duplicative.
55
+ puts "[AGENT RESPONSE] #{output.response}" if config.show_response? && !config.show_progress?
56
+ puts "[AGENT STATS] #{output.stats}" if config.show_stats?
57
+ puts "Session ID: #{output.session}" if config.show_stats?
58
+ output
59
+ end
60
+
61
+ private
62
+
63
+ #: () -> Provider
64
+ def provider
65
+ @provider ||= case config.valid_provider!
66
+ when :claude
67
+ Providers::Claude.new(config)
68
+ else
69
+ raise UnknownProviderError, "Unknown provider: #{config.valid_provider!}"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end