roast-ai 0.4.9 → 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.
- checksums.yaml +4 -4
- data/.claude/commands/docs/write-comments.md +36 -0
- data/.github/CODEOWNERS +1 -1
- data/.github/workflows/ci.yaml +10 -6
- data/.gitignore +0 -1
- data/.rubocop.yml +7 -1
- data/CLAUDE.md +2 -2
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +18 -18
- data/Gemfile.lock +46 -57
- data/README.md +118 -1432
- data/README_LEGACY.md +1464 -0
- data/Rakefile +39 -4
- data/dev.yml +29 -0
- data/dsl/agent_sessions.rb +20 -0
- data/dsl/async_cogs.rb +49 -0
- data/dsl/async_cogs_complex.rb +67 -0
- data/dsl/call.rb +44 -0
- data/dsl/collect_from.rb +72 -0
- data/dsl/demo/Gemfile +4 -0
- data/dsl/demo/Gemfile.lock +120 -0
- data/dsl/demo/cogs/local.rb +15 -0
- data/dsl/demo/simple_external_cog.rb +17 -0
- data/dsl/json_output.rb +28 -0
- data/dsl/map.rb +55 -0
- data/dsl/map_reduce.rb +37 -0
- data/dsl/map_with_index.rb +49 -0
- data/dsl/next_break.rb +40 -0
- data/dsl/next_break_parallel.rb +44 -0
- data/dsl/outputs.rb +39 -0
- data/dsl/outputs_bang.rb +36 -0
- data/dsl/parallel_map.rb +37 -0
- data/dsl/plugin-gem-example/.gitignore +8 -0
- data/dsl/plugin-gem-example/Gemfile +13 -0
- data/dsl/plugin-gem-example/Gemfile.lock +178 -0
- data/dsl/plugin-gem-example/lib/other.rb +17 -0
- data/dsl/plugin-gem-example/lib/plugin_gem_example.rb +5 -0
- data/dsl/plugin-gem-example/lib/simple.rb +15 -0
- data/dsl/plugin-gem-example/lib/version.rb +10 -0
- data/dsl/plugin-gem-example/plugin-gem-example.gemspec +28 -0
- data/dsl/prompts/simple_prompt.md.erb +3 -0
- data/dsl/prototype.rb +10 -4
- data/dsl/repeat_loop_results.rb +53 -0
- data/dsl/ruby_cog.rb +72 -0
- data/dsl/simple_agent.rb +18 -0
- data/dsl/simple_chat.rb +26 -0
- data/dsl/simple_repeat.rb +29 -0
- data/dsl/skip.rb +36 -0
- data/dsl/step_communication.rb +10 -5
- data/dsl/targets_and_params.rb +57 -0
- data/dsl/temperature.rb +17 -0
- data/dsl/temporary_directory.rb +22 -0
- data/dsl/tutorial/01_your_first_workflow/README.md +179 -0
- data/dsl/tutorial/01_your_first_workflow/configured_chat.rb +33 -0
- data/dsl/tutorial/01_your_first_workflow/hello.rb +23 -0
- data/dsl/tutorial/02_chaining_cogs/README.md +310 -0
- data/dsl/tutorial/02_chaining_cogs/code_review.rb +104 -0
- data/dsl/tutorial/02_chaining_cogs/session_resumption.rb +92 -0
- data/dsl/tutorial/02_chaining_cogs/simple_chain.rb +84 -0
- data/dsl/tutorial/03_targets_and_params/README.md +230 -0
- data/dsl/tutorial/03_targets_and_params/multiple_targets.rb +65 -0
- data/dsl/tutorial/03_targets_and_params/single_target.rb +65 -0
- data/dsl/tutorial/04_configuration_options/README.md +209 -0
- data/dsl/tutorial/04_configuration_options/control_display_and_temperature.rb +104 -0
- data/dsl/tutorial/04_configuration_options/simple_config.rb +68 -0
- data/dsl/tutorial/05_control_flow/README.md +156 -0
- data/dsl/tutorial/05_control_flow/conditional_execution.rb +62 -0
- data/dsl/tutorial/05_control_flow/handling_failures.rb +77 -0
- data/dsl/tutorial/06_reusable_scopes/README.md +172 -0
- data/dsl/tutorial/06_reusable_scopes/accessing_scope_outputs.rb +126 -0
- data/dsl/tutorial/06_reusable_scopes/basic_scope.rb +63 -0
- data/dsl/tutorial/06_reusable_scopes/parameterized_scope.rb +78 -0
- data/dsl/tutorial/07_processing_collections/README.md +152 -0
- data/dsl/tutorial/07_processing_collections/basic_map.rb +70 -0
- data/dsl/tutorial/07_processing_collections/parallel_map.rb +74 -0
- data/dsl/tutorial/08_iterative_workflows/README.md +231 -0
- data/dsl/tutorial/08_iterative_workflows/basic_repeat.rb +57 -0
- data/dsl/tutorial/08_iterative_workflows/conditional_break.rb +57 -0
- data/dsl/tutorial/09_async_cogs/README.md +197 -0
- data/dsl/tutorial/09_async_cogs/basic_async.rb +38 -0
- data/dsl/tutorial/README.md +222 -0
- data/dsl/working_directory.rb +16 -0
- data/exe/roast +1 -1
- data/internal/documentation/architectural-notes.md +115 -0
- data/internal/documentation/doc-comments-external.md +686 -0
- data/internal/documentation/doc-comments-internal.md +342 -0
- data/internal/documentation/doc-comments.md +211 -0
- data/lib/roast/dsl/cog/config.rb +280 -4
- data/lib/roast/dsl/cog/input.rb +73 -0
- data/lib/roast/dsl/cog/output.rb +313 -0
- data/lib/roast/dsl/cog/registry.rb +71 -0
- data/lib/roast/dsl/cog/stack.rb +3 -2
- data/lib/roast/dsl/cog/store.rb +11 -8
- data/lib/roast/dsl/cog.rb +108 -31
- data/lib/roast/dsl/cog_input_context.rb +44 -0
- data/lib/roast/dsl/cog_input_manager.rb +156 -0
- data/lib/roast/dsl/cogs/agent/config.rb +465 -0
- data/lib/roast/dsl/cogs/agent/input.rb +81 -0
- data/lib/roast/dsl/cogs/agent/output.rb +59 -0
- data/lib/roast/dsl/cogs/agent/provider.rb +51 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/claude_invocation.rb +185 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/message.rb +73 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/assistant_message.rb +36 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/result_message.rb +61 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/system_message.rb +47 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/text_message.rb +36 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_result_message.rb +47 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_use_message.rb +46 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/unknown_message.rb +27 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/messages/user_message.rb +37 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/tool_result.rb +51 -0
- data/lib/roast/dsl/cogs/agent/providers/claude/tool_use.rb +48 -0
- data/lib/roast/dsl/cogs/agent/providers/claude.rb +31 -0
- data/lib/roast/dsl/cogs/agent/stats.rb +92 -0
- data/lib/roast/dsl/cogs/agent/usage.rb +62 -0
- data/lib/roast/dsl/cogs/agent.rb +75 -0
- data/lib/roast/dsl/cogs/chat/config.rb +453 -0
- data/lib/roast/dsl/cogs/chat/input.rb +92 -0
- data/lib/roast/dsl/cogs/chat/output.rb +64 -0
- data/lib/roast/dsl/cogs/chat/session.rb +68 -0
- data/lib/roast/dsl/cogs/chat.rb +81 -0
- data/lib/roast/dsl/cogs/cmd.rb +291 -27
- data/lib/roast/dsl/cogs/ruby.rb +171 -0
- data/lib/roast/dsl/command_runner.rb +191 -0
- data/lib/roast/dsl/config_context.rb +2 -47
- data/lib/roast/dsl/config_manager.rb +143 -0
- data/lib/roast/dsl/control_flow.rb +41 -0
- data/lib/roast/dsl/execution_context.rb +9 -0
- data/lib/roast/dsl/execution_manager.rb +267 -0
- data/lib/roast/dsl/nil_assertions.rb +23 -0
- data/lib/roast/dsl/system_cog/params.rb +32 -0
- data/lib/roast/dsl/system_cog.rb +36 -0
- data/lib/roast/dsl/system_cogs/call.rb +162 -0
- data/lib/roast/dsl/system_cogs/map.rb +448 -0
- data/lib/roast/dsl/system_cogs/repeat.rb +242 -0
- data/lib/roast/dsl/workflow.rb +123 -0
- data/lib/roast/dsl/workflow_context.rb +20 -0
- data/lib/roast/dsl/workflow_params.rb +24 -0
- data/lib/roast/sorbet_runtime_stub.rb +154 -0
- data/lib/roast/tools/apply_diff.rb +1 -3
- data/lib/roast/tools/cmd.rb +4 -3
- data/lib/roast/tools/read_file.rb +1 -1
- data/lib/roast/tools/update_files.rb +1 -1
- data/lib/roast/tools/write_file.rb +1 -1
- data/lib/roast/version.rb +1 -1
- data/lib/roast/workflow/base_workflow.rb +4 -0
- data/lib/roast/workflow/step_loader.rb +14 -2
- data/lib/roast-ai.rb +4 -0
- data/lib/roast.rb +60 -22
- data/{roast.gemspec → roast-ai.gemspec} +10 -13
- data/sorbet/config +1 -0
- data/sorbet/rbi/gems/async@2.34.0.rbi +1577 -0
- data/sorbet/rbi/gems/cli-kit@5.2.0.rbi +2063 -0
- data/sorbet/rbi/gems/{cli-ui@2.3.0.rbi → cli-ui@2.7.0-6bdefd1d06305e5d6ae312ac76f9c88f88658dda.rbi} +1418 -1013
- data/sorbet/rbi/gems/console@1.34.2.rbi +1193 -0
- data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +50 -0
- data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +35 -0
- data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +41 -0
- data/sorbet/rbi/gems/io-event@1.14.0.rbi +724 -0
- data/sorbet/rbi/gems/marcel@1.1.0.rbi +239 -0
- data/sorbet/rbi/gems/metrics@0.15.0.rbi +9 -0
- data/sorbet/rbi/gems/ruby_llm@1.8.2.rbi +5703 -0
- data/sorbet/rbi/gems/traces@0.18.2.rbi +9 -0
- data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +1197 -0
- data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +314 -2
- data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +498 -0
- data/sorbet/tapioca/config.yml +6 -0
- data/sorbet/tapioca/require.rb +2 -0
- metadata +198 -34
- data/dsl/less_simple.rb +0 -112
- data/dsl/simple.rb +0 -8
- data/lib/roast/dsl/cog_execution_context.rb +0 -29
- data/lib/roast/dsl/cogs/graph.rb +0 -53
- data/lib/roast/dsl/cogs.rb +0 -65
- data/lib/roast/dsl/executor.rb +0 -82
- data/lib/roast/dsl/workflow_execution_context.rb +0 -47
- data/sorbet/rbi/gems/cgi@0.5.0.rbi +0 -2961
- data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +0 -568
- data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +0 -1991
- data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +0 -672
- data/sorbet/rbi/gems/dry-core@1.1.0.rbi +0 -1894
- data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +0 -659
- data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +0 -781
- data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +0 -1127
- data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +0 -3727
- data/sorbet/rbi/gems/dry-types@1.8.3.rbi +0 -3969
- data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +0 -1588
- data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +0 -136
- data/sorbet/rbi/gems/mime-types@3.7.0.rbi +0 -1342
- data/sorbet/rbi/gems/rack@2.2.18.rbi +0 -5659
- data/sorbet/rbi/gems/rbs-inline@0.12.0.rbi +0 -2170
- data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +0 -435
- data/sorbet/rbi/gems/yard@0.9.37.rbi +0 -18492
- data/sorbet/rbi/shims/lib/roast/dsl/workflow_execution_context.rbi +0 -11
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Roast
|
|
5
|
+
module DSL
|
|
6
|
+
class Workflow
|
|
7
|
+
class WorkflowError < Roast::Error; end
|
|
8
|
+
class WorkflowNotPreparedError < WorkflowError; end
|
|
9
|
+
class WorkflowAlreadyPreparedError < WorkflowError; end
|
|
10
|
+
class WorkflowAlreadyStartedError < WorkflowError; end
|
|
11
|
+
class InvalidCogReference < WorkflowError; end
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
#: (String, WorkflowParams) -> void
|
|
15
|
+
def from_file(workflow_path, params)
|
|
16
|
+
Dir.mktmpdir("roast-") do |tmpdir|
|
|
17
|
+
workflow_context = WorkflowContext.new(params:, tmpdir:)
|
|
18
|
+
workflow = new(workflow_path, workflow_context)
|
|
19
|
+
workflow.prepare!
|
|
20
|
+
workflow.start!
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#: (String, WorkflowContext) -> void
|
|
26
|
+
def initialize(workflow_path, workflow_context)
|
|
27
|
+
@workflow_path = Pathname.new(workflow_path) #: Pathname
|
|
28
|
+
@workflow_context = workflow_context #: WorkflowContext
|
|
29
|
+
@workflow_definition = File.read(workflow_path) #: String
|
|
30
|
+
@cog_registry = Cog::Registry.new #: Cog::Registry
|
|
31
|
+
@config_procs = [] #: Array[^() -> void]
|
|
32
|
+
@execution_procs = { nil: [] } #: Hash[Symbol?, Array[^() -> void]]
|
|
33
|
+
@config_manager = nil #: ConfigManager?
|
|
34
|
+
@execution_manager = nil #: ExecutionManager?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#: () -> void
|
|
38
|
+
def prepare!
|
|
39
|
+
raise WorkflowAlreadyPreparedError if preparing? || prepared?
|
|
40
|
+
|
|
41
|
+
@preparing = true
|
|
42
|
+
extract_dsl_procs!
|
|
43
|
+
@config_manager = ConfigManager.new(@cog_registry, @config_procs)
|
|
44
|
+
@config_manager.not_nil!.prepare!
|
|
45
|
+
# TODO: probably we should just not pass the params as the top-level scope value anymore
|
|
46
|
+
@execution_manager = ExecutionManager.new(@cog_registry, @config_manager.not_nil!, @execution_procs, @workflow_context, scope_value: @workflow_context.params)
|
|
47
|
+
@execution_manager.not_nil!.prepare!
|
|
48
|
+
|
|
49
|
+
@prepared = true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
#: () -> void
|
|
53
|
+
def start!
|
|
54
|
+
raise WorkflowNotPreparedError unless @config_manager.present? && @execution_manager.present?
|
|
55
|
+
raise WorkflowAlreadyStartedError if started? || completed?
|
|
56
|
+
|
|
57
|
+
@started = true
|
|
58
|
+
begin
|
|
59
|
+
@execution_manager.run!
|
|
60
|
+
rescue ControlFlow::Break
|
|
61
|
+
# treat `break!` like `next!` in the top-level executor scope
|
|
62
|
+
# TODO: maybe do something with the message passed to break!
|
|
63
|
+
end
|
|
64
|
+
@completed = true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#: () -> bool
|
|
68
|
+
def preparing?
|
|
69
|
+
@preparing ||= false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#: () -> bool
|
|
73
|
+
def prepared?
|
|
74
|
+
@prepared ||= false
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#: () -> bool
|
|
78
|
+
def started?
|
|
79
|
+
@started ||= false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#: () -> bool
|
|
83
|
+
def completed?
|
|
84
|
+
@completed ||= false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
#: { () [self: Roast::DSL::ConfigContext] -> void } -> void
|
|
88
|
+
def config(&block)
|
|
89
|
+
@config_procs << block
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#: (?Symbol?) { () [self: Roast::DSL::ExecutionContext] -> void } -> void
|
|
93
|
+
def execute(scope = nil, &block)
|
|
94
|
+
(@execution_procs[scope] ||= []) << block
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def use(cogs = [], from: nil)
|
|
98
|
+
require from if from
|
|
99
|
+
|
|
100
|
+
Array.wrap(cogs).each do |cog_name|
|
|
101
|
+
path = @workflow_path.realdirpath.dirname.join("cogs/#{cog_name}")
|
|
102
|
+
require path.to_s if from.nil?
|
|
103
|
+
|
|
104
|
+
cog_class_name = cog_name.camelize
|
|
105
|
+
raise InvalidCogReference, "Expected #{cog_class_name} class, not found in #{path}" unless Object.const_defined?(cog_class_name)
|
|
106
|
+
|
|
107
|
+
cog_class = cog_class_name.constantize # rubocop:disable Sorbet/ConstantsFromStrings
|
|
108
|
+
@cog_registry.use(cog_class)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
# Evaluate the top-level workflow definition
|
|
115
|
+
# This collects the procs passed to `config` and `execute` calls in the workflow definition,
|
|
116
|
+
# but does not evaluate any of them individually yet.
|
|
117
|
+
#: () -> void
|
|
118
|
+
def extract_dsl_procs!
|
|
119
|
+
instance_eval(@workflow_definition, @workflow_path.realpath.to_s, 1)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Roast
|
|
5
|
+
module DSL
|
|
6
|
+
class WorkflowContext
|
|
7
|
+
#: WorkflowParams
|
|
8
|
+
attr_reader :params
|
|
9
|
+
|
|
10
|
+
#: String
|
|
11
|
+
attr_reader :tmpdir
|
|
12
|
+
|
|
13
|
+
#: (params: WorkflowParams, tmpdir: String) -> void
|
|
14
|
+
def initialize(params:, tmpdir:)
|
|
15
|
+
@params = params
|
|
16
|
+
@tmpdir = tmpdir
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Roast
|
|
5
|
+
module DSL
|
|
6
|
+
class WorkflowParams
|
|
7
|
+
#: Array[String]
|
|
8
|
+
attr_reader :targets
|
|
9
|
+
|
|
10
|
+
#: Array[Symbol]
|
|
11
|
+
attr_reader :args
|
|
12
|
+
|
|
13
|
+
#: Hash[Symbol, String]
|
|
14
|
+
attr_reader :kwargs
|
|
15
|
+
|
|
16
|
+
#: (Array[String], Array[Symbol], Hash[Symbol, String]) -> void
|
|
17
|
+
def initialize(targets, args, kwargs)
|
|
18
|
+
@targets = targets
|
|
19
|
+
@args = args
|
|
20
|
+
@kwargs = kwargs
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# typed: ignore
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module T
|
|
5
|
+
class << self
|
|
6
|
+
def absurd(value); end
|
|
7
|
+
def all(type_a, type_b, *types); end
|
|
8
|
+
def any(type_a, type_b, *types); end
|
|
9
|
+
def attached_class; end
|
|
10
|
+
def class_of(klass); end
|
|
11
|
+
def enum(values); end
|
|
12
|
+
def nilable(type); end
|
|
13
|
+
def noreturn; end
|
|
14
|
+
def self_type; end
|
|
15
|
+
def type_alias(type = nil, &_blk); end
|
|
16
|
+
def type_parameter(name); end
|
|
17
|
+
def untyped; end
|
|
18
|
+
|
|
19
|
+
def assert_type!(value, _type, _checked: true)
|
|
20
|
+
value
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cast(value, _type, _checked: true)
|
|
24
|
+
value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def let(value, _type, _checked: true)
|
|
28
|
+
value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def must(arg, _msg = nil)
|
|
32
|
+
arg
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def proc
|
|
36
|
+
T::Proc.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def reveal_type(value)
|
|
40
|
+
value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def unsafe(value)
|
|
44
|
+
value
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module Sig
|
|
49
|
+
def sig(arg0 = nil, &blk); end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module Helpers
|
|
53
|
+
def abstract!; end
|
|
54
|
+
def interface!; end
|
|
55
|
+
def final!; end
|
|
56
|
+
def sealed!; end
|
|
57
|
+
def mixes_in_class_methods(mod); end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module Generic
|
|
61
|
+
include(T::Helpers)
|
|
62
|
+
|
|
63
|
+
def type_parameters(*params); end
|
|
64
|
+
def type_member(variance = :invariant, fixed: nil, lower: nil, upper: BasicObject); end
|
|
65
|
+
def type_template(variance = :invariant, fixed: nil, lower: nil, upper: BasicObject); end
|
|
66
|
+
|
|
67
|
+
def [](*types)
|
|
68
|
+
self
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
module Array
|
|
73
|
+
class << self
|
|
74
|
+
def [](type); end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
Boolean = Object.new.freeze
|
|
79
|
+
|
|
80
|
+
module Configuration
|
|
81
|
+
class << self
|
|
82
|
+
def call_validation_error_handler(signature, opts); end
|
|
83
|
+
def call_validation_error_handler=(value); end
|
|
84
|
+
def default_checked_level=(default_checked_level); end
|
|
85
|
+
def enable_checking_for_sigs_marked_checked_tests; end
|
|
86
|
+
def enable_final_checks_on_hooks; end
|
|
87
|
+
def enable_legacy_t_enum_migration_mode; end
|
|
88
|
+
def reset_final_checks_on_hooks; end
|
|
89
|
+
def hard_assert_handler(str, extra); end
|
|
90
|
+
def hard_assert_handler=(value); end
|
|
91
|
+
def inline_type_error_handler(error); end
|
|
92
|
+
def inline_type_error_handler=(value); end
|
|
93
|
+
def log_info_handler(str, extra); end
|
|
94
|
+
def log_info_handler=(value); end
|
|
95
|
+
def scalar_types; end
|
|
96
|
+
def scalar_types=(values); end
|
|
97
|
+
def sealed_violation_whitelist; end
|
|
98
|
+
def sealed_violation_whitelist=(sealed_violation_whitelist); end
|
|
99
|
+
def sig_builder_error_handler=(value); end
|
|
100
|
+
def sig_validation_error_handler(error, opts); end
|
|
101
|
+
def sig_validation_error_handler=(value); end
|
|
102
|
+
def soft_assert_handler(str, extra); end
|
|
103
|
+
def soft_assert_handler=(value); end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
module Enumerable
|
|
108
|
+
class << self
|
|
109
|
+
def [](type); end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
module Enumerator
|
|
114
|
+
class << self
|
|
115
|
+
def [](type); end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
module Hash
|
|
120
|
+
class << self
|
|
121
|
+
def [](keys, values); end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
class Proc
|
|
126
|
+
def bind(*_)
|
|
127
|
+
self
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def params(*_param)
|
|
131
|
+
self
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def void
|
|
135
|
+
self
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def returns(_type)
|
|
139
|
+
self
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
module Range
|
|
144
|
+
class << self
|
|
145
|
+
def [](type); end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
module Set
|
|
150
|
+
class << self
|
|
151
|
+
def [](type); end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# typed: false
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require "cli/ui"
|
|
5
|
-
|
|
6
4
|
module Roast
|
|
7
5
|
module Tools
|
|
8
6
|
module ApplyDiff
|
|
@@ -64,7 +62,7 @@ module Roast
|
|
|
64
62
|
Roast::Helpers::Logger.info(cancel_msg + "\n")
|
|
65
63
|
cancel_msg
|
|
66
64
|
end
|
|
67
|
-
rescue Roast::Error => e
|
|
65
|
+
rescue Roast::Error, Errno::EACCES, Errno::ENOENT => e
|
|
68
66
|
error_message = "Error applying diff: #{e.message}"
|
|
69
67
|
Roast::Helpers::Logger.error(error_message + "\n")
|
|
70
68
|
Roast::Helpers::Logger.debug(e.backtrace.join("\n") + "\n") if ENV["DEBUG"]
|
data/lib/roast/tools/cmd.rb
CHANGED
|
@@ -153,9 +153,10 @@ module Roast
|
|
|
153
153
|
)
|
|
154
154
|
|
|
155
155
|
format_output(command, result, status.exitstatus)
|
|
156
|
-
rescue Timeout::Error => e
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
rescue Timeout::Error, Errno::ENOENT => e
|
|
157
|
+
error_message = "Error running command: #{e.message}"
|
|
158
|
+
Roast::Helpers::Logger.error(error_message + "\n")
|
|
159
|
+
error_message
|
|
159
160
|
end
|
|
160
161
|
|
|
161
162
|
def format_output(command, result, exit_status)
|
|
@@ -39,7 +39,7 @@ module Roast
|
|
|
39
39
|
else
|
|
40
40
|
File.read(path)
|
|
41
41
|
end
|
|
42
|
-
rescue Roast::Error => e
|
|
42
|
+
rescue Roast::Error, Errno::ENOENT, Errno::EACCES => e
|
|
43
43
|
"Error reading file: #{e.message}".tap do |error_message|
|
|
44
44
|
Roast::Helpers::Logger.error(error_message + "\n")
|
|
45
45
|
Roast::Helpers::Logger.debug(e.backtrace.join("\n") + "\n") if ENV["DEBUG"]
|
|
@@ -49,7 +49,7 @@ module Roast
|
|
|
49
49
|
Roast::Helpers::Logger.error(restriction_message)
|
|
50
50
|
"Error: Path must start with '#{restrict_path}' to use the write_file tool, try again."
|
|
51
51
|
end
|
|
52
|
-
rescue Roast::Error => e
|
|
52
|
+
rescue Roast::Error, Errno::EACCES, Errno::ENOENT => e
|
|
53
53
|
"Error writing file: #{e.message}".tap do |error_message|
|
|
54
54
|
Roast::Helpers::Logger.error(error_message + "\n")
|
|
55
55
|
Roast::Helpers::Logger.debug(e.backtrace.join("\n") + "\n") if ENV["DEBUG"]
|
data/lib/roast/version.rb
CHANGED
|
@@ -169,7 +169,14 @@ module Roast
|
|
|
169
169
|
raise StepExecutionError.new("Syntax error in step file: #{e.message}", step_name: step_name, original_error: e)
|
|
170
170
|
end
|
|
171
171
|
|
|
172
|
-
step_class = step_name.
|
|
172
|
+
step_class = if Object.const_defined?(step_name.camelize, false)
|
|
173
|
+
step_name.camelize.constantize
|
|
174
|
+
elsif Object.const_defined?(step_name.classify, false)
|
|
175
|
+
step_name.classify.constantize
|
|
176
|
+
else
|
|
177
|
+
raise StepExecutionError.new("No class named #{step_name.camelize} found in step file #{file_path}", step_name: step_name)
|
|
178
|
+
end
|
|
179
|
+
|
|
173
180
|
context = File.dirname(file_path)
|
|
174
181
|
# For Ruby steps, we instantiate the specific class directly
|
|
175
182
|
# Convert step_name to StepName value object
|
|
@@ -208,7 +215,12 @@ module Roast
|
|
|
208
215
|
def configure_step(step, step_name, is_last_step: nil)
|
|
209
216
|
step_config = config_hash[step_name]
|
|
210
217
|
|
|
211
|
-
#
|
|
218
|
+
# Apply global model if no step-specific model is configured
|
|
219
|
+
if config_hash.key?("model") && !step_config&.key?("model")
|
|
220
|
+
step.model = config_hash["model"]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Apply step-specific model (overrides global model)
|
|
212
224
|
step.model = step_config["model"] if step_config&.key?("model")
|
|
213
225
|
|
|
214
226
|
# Pass resource to step if supported
|
data/lib/roast-ai.rb
ADDED
data/lib/roast.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
# Standard library requires
|
|
5
|
+
require "benchmark"
|
|
5
6
|
require "digest"
|
|
6
7
|
require "English"
|
|
7
8
|
require "erb"
|
|
@@ -11,6 +12,7 @@ require "logger"
|
|
|
11
12
|
require "net/http"
|
|
12
13
|
require "open3"
|
|
13
14
|
require "pathname"
|
|
15
|
+
require "pp"
|
|
14
16
|
require "securerandom"
|
|
15
17
|
require "shellwords"
|
|
16
18
|
require "tempfile"
|
|
@@ -28,23 +30,37 @@ require "active_support/core_ext/string"
|
|
|
28
30
|
require "active_support/core_ext/string/inflections"
|
|
29
31
|
require "active_support/isolated_execution_state"
|
|
30
32
|
require "active_support/notifications"
|
|
31
|
-
require "
|
|
33
|
+
require "async"
|
|
34
|
+
require "async/semaphore"
|
|
32
35
|
require "cli/kit"
|
|
36
|
+
require "cli/ui"
|
|
33
37
|
require "diff/lcs"
|
|
34
38
|
require "json-schema"
|
|
35
39
|
require "raix"
|
|
36
40
|
require "raix/chat_completion"
|
|
37
41
|
require "raix/function_dispatch"
|
|
38
42
|
require "ruby-graphviz"
|
|
43
|
+
require "ruby_llm"
|
|
39
44
|
require "thor"
|
|
40
45
|
require "timeout"
|
|
41
46
|
|
|
47
|
+
unless defined?(T)
|
|
48
|
+
# NOTE: stubs for sorbet-runtime were being imported from cli-kit. They were removed in cli-kit v5.2
|
|
49
|
+
# Ideally we will not need them at all in the future, but for now I have brought them into the project
|
|
50
|
+
# because a large quantity of legacy code is using sorbet runtime assertions.
|
|
51
|
+
require("roast/sorbet_runtime_stub")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Require project components that will not get automatically loaded
|
|
55
|
+
require "roast/dsl/nil_assertions"
|
|
56
|
+
|
|
42
57
|
# Autoloading setup
|
|
43
58
|
require "zeitwerk"
|
|
44
59
|
|
|
45
60
|
# Set up Zeitwerk autoloader
|
|
46
61
|
loader = Zeitwerk::Loader.for_gem
|
|
47
62
|
loader.inflector.inflect("dsl" => "DSL")
|
|
63
|
+
loader.ignore("#{__dir__}/roast-ai.rb")
|
|
48
64
|
loader.setup
|
|
49
65
|
|
|
50
66
|
module Roast
|
|
@@ -59,7 +75,7 @@ module Roast
|
|
|
59
75
|
option :replay, type: :string, aliases: "-r", desc: "Resume workflow from a specific step. Format: step_name or session_timestamp:step_name"
|
|
60
76
|
option :pause, type: :string, aliases: "-p", desc: "Pause workflow after a specific step. Format: step_name"
|
|
61
77
|
option :file_storage, type: :boolean, aliases: "-f", desc: "Use filesystem storage for sessions instead of SQLite"
|
|
62
|
-
option :executor, type: :string, default: "default", desc: "Set workflow executor
|
|
78
|
+
option :executor, type: :string, default: "default", desc: "Set workflow executor (use 'dsl' for Roast 1.0 Feature Preview)"
|
|
63
79
|
|
|
64
80
|
def execute(*paths)
|
|
65
81
|
raise Thor::Error, "Workflow configuration file is required" if paths.empty?
|
|
@@ -67,8 +83,13 @@ module Roast
|
|
|
67
83
|
workflow_path, *files = paths
|
|
68
84
|
|
|
69
85
|
if options[:executor] == "dsl"
|
|
70
|
-
puts "⚠️ WARNING:
|
|
71
|
-
|
|
86
|
+
$stderr.puts "⚠️ WARNING: You are using Roast 1.0 feature preview. This syntax has not yet been officially released and should not be considered fully stable."
|
|
87
|
+
targets, workflow_args, workflow_kwargs = parse_custom_workflow_args(files, ARGV)
|
|
88
|
+
targets.unshift(options[:target]) if options[:target]
|
|
89
|
+
workflow_params = Roast::DSL::WorkflowParams.new(targets, workflow_args, workflow_kwargs)
|
|
90
|
+
Dir.chdir(ENV["ROAST_WORKING_DIRECTORY"] || Dir.pwd) do
|
|
91
|
+
Roast::DSL::Workflow.from_file(workflow_path, workflow_params)
|
|
92
|
+
end
|
|
72
93
|
else
|
|
73
94
|
expanded_workflow_path = if workflow_path.include?("workflow.yml")
|
|
74
95
|
File.expand_path(workflow_path)
|
|
@@ -286,6 +307,24 @@ module Roast
|
|
|
286
307
|
|
|
287
308
|
private
|
|
288
309
|
|
|
310
|
+
#: (Array[String], Array[String]) -> [Array[String], Array[Symbol], Hash[Symbol, String]]
|
|
311
|
+
def parse_custom_workflow_args(parsed_args, raw_args)
|
|
312
|
+
separator_index = raw_args.index("--")
|
|
313
|
+
extra_args = (separator_index ? raw_args[(separator_index + 1)..] : []) || []
|
|
314
|
+
targets = parsed_args.shift(parsed_args.length - extra_args.length)
|
|
315
|
+
args = []
|
|
316
|
+
kwargs = {}
|
|
317
|
+
parsed_args.each do |arg|
|
|
318
|
+
if arg.include?("=")
|
|
319
|
+
key, value = arg.split("=", 2)
|
|
320
|
+
kwargs[key.to_sym] = value if key
|
|
321
|
+
else
|
|
322
|
+
args << arg.to_sym
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
[targets, args, kwargs]
|
|
326
|
+
end
|
|
327
|
+
|
|
289
328
|
def show_example_picker
|
|
290
329
|
examples = available_examples
|
|
291
330
|
|
|
@@ -295,7 +334,7 @@ module Roast
|
|
|
295
334
|
end
|
|
296
335
|
|
|
297
336
|
puts "Select an option:"
|
|
298
|
-
choices = ["Pick from examples", "New from prompt (
|
|
337
|
+
choices = ["Pick from examples", "New from prompt (coming soon)"]
|
|
299
338
|
|
|
300
339
|
selected = run_picker(choices, "Select initialization method:")
|
|
301
340
|
|
|
@@ -303,8 +342,8 @@ module Roast
|
|
|
303
342
|
when "Pick from examples"
|
|
304
343
|
example_choice = run_picker(examples, "Select an example:")
|
|
305
344
|
copy_example(example_choice) if example_choice
|
|
306
|
-
when "New from prompt (
|
|
307
|
-
|
|
345
|
+
when "New from prompt (coming soon)"
|
|
346
|
+
show_coming_soon_message
|
|
308
347
|
end
|
|
309
348
|
end
|
|
310
349
|
|
|
@@ -348,22 +387,21 @@ module Roast
|
|
|
348
387
|
puts "Successfully copied example '#{example_name}' to current directory."
|
|
349
388
|
end
|
|
350
389
|
|
|
351
|
-
def
|
|
352
|
-
puts
|
|
390
|
+
def show_coming_soon_message
|
|
391
|
+
puts
|
|
392
|
+
puts ::CLI::UI.fmt("{{bold:Workflow Generator - Coming Soon}}")
|
|
393
|
+
puts
|
|
394
|
+
puts "The 'New from prompt' workflow generator is being rebuilt to ensure"
|
|
395
|
+
puts "generated workflows are reliable and properly validated."
|
|
396
|
+
puts
|
|
397
|
+
puts "This feature will return with:"
|
|
398
|
+
puts " • Better AI-generated workflow quality"
|
|
399
|
+
puts " • Validation to ensure generated workflows actually work"
|
|
400
|
+
puts " • Integration with Roast's upcoming DSL features"
|
|
401
|
+
puts
|
|
402
|
+
puts "For now, please use 'Pick from examples' to get started."
|
|
403
|
+
puts "You can then customize the example workflow for your needs."
|
|
353
404
|
puts
|
|
354
|
-
|
|
355
|
-
# Execute the workflow generator
|
|
356
|
-
generator_path = File.join(Roast::ROOT, "examples", "workflow_generator", "workflow.yml")
|
|
357
|
-
|
|
358
|
-
begin
|
|
359
|
-
# Execute the workflow generator (it will handle user input)
|
|
360
|
-
Roast::Workflow::WorkflowRunner.new(generator_path, [], {}).begin!
|
|
361
|
-
|
|
362
|
-
puts
|
|
363
|
-
puts("Workflow generation complete!")
|
|
364
|
-
rescue => e
|
|
365
|
-
puts("Error generating workflow: #{e.message}")
|
|
366
|
-
end
|
|
367
405
|
end
|
|
368
406
|
|
|
369
407
|
class << self
|
|
@@ -15,17 +15,10 @@ Gem::Specification.new do |spec|
|
|
|
15
15
|
spec.homepage = "https://github.com/Shopify/roast"
|
|
16
16
|
spec.license = "MIT"
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
23
|
-
spec.metadata["source_code_uri"] = "https://github.com/Shopify/roast"
|
|
24
|
-
spec.metadata["changelog_uri"] = "https://github.com/Shopify/roast/blob/main/CHANGELOG.md"
|
|
25
|
-
else
|
|
26
|
-
raise "RubyGems 2.0 or newer is required to protect against " \
|
|
27
|
-
"public gem pushes."
|
|
28
|
-
end
|
|
18
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/Shopify/roast"
|
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/Shopify/roast/blob/main/CHANGELOG.md"
|
|
29
22
|
|
|
30
23
|
# Specify which files should be added to the gem when it is released.
|
|
31
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
@@ -37,13 +30,17 @@ Gem::Specification.new do |spec|
|
|
|
37
30
|
spec.require_paths = ["lib"]
|
|
38
31
|
|
|
39
32
|
spec.add_dependency("activesupport", ">= 7.0")
|
|
40
|
-
spec.add_dependency("
|
|
41
|
-
spec.add_dependency("
|
|
33
|
+
spec.add_dependency("async", "~> 2.34")
|
|
34
|
+
spec.add_dependency("benchmark", "~> 0.4.1")
|
|
35
|
+
spec.add_dependency("cli-kit", "~> 5.2")
|
|
36
|
+
spec.add_dependency("cli-ui", "~> 2.7")
|
|
42
37
|
spec.add_dependency("diff-lcs", "~> 1.5")
|
|
43
38
|
spec.add_dependency("json-schema")
|
|
44
39
|
spec.add_dependency("open_router", "~> 0.3")
|
|
45
40
|
spec.add_dependency("raix", "~> 1.0.2")
|
|
41
|
+
spec.add_dependency("rake", "~> 13.3.0") # NOTE: required by Thor
|
|
46
42
|
spec.add_dependency("ruby-graphviz", "~> 1.2")
|
|
43
|
+
spec.add_dependency("ruby_llm")
|
|
47
44
|
spec.add_dependency("sqlite3", "~> 2.6")
|
|
48
45
|
spec.add_dependency("thor", "~> 1.3")
|
|
49
46
|
spec.add_dependency("zeitwerk", "~> 2.6")
|