solid_agents 0.1.0 → 0.2.1

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -1
  3. data/README.md +52 -40
  4. data/app/controllers/solid_agents/runs_controller.rb +4 -1
  5. data/app/jobs/solid_agents/execute_run_job.rb +2 -0
  6. data/app/models/solid_agents/agent.rb +1 -1
  7. data/app/models/solid_agents/handoff.rb +11 -0
  8. data/app/models/solid_agents/run.rb +38 -3
  9. data/app/models/solid_agents/work_item.rb +11 -0
  10. data/app/services/solid_agents/runs/dispatch.rb +5 -2
  11. data/app/services/solid_agents/runs/executor.rb +41 -9
  12. data/app/services/solid_agents/runs/prompt_builder.rb +5 -11
  13. data/app/solid_agents/agents/alex.rb +11 -0
  14. data/app/solid_agents/agents/base.rb +28 -0
  15. data/app/solid_agents/agents/betty.rb +11 -0
  16. data/app/solid_agents/agents/chad.rb +11 -0
  17. data/app/solid_agents/agents/david.rb +11 -0
  18. data/app/solid_agents/agents/eddy.rb +11 -0
  19. data/app/solid_agents/agents.rb +26 -0
  20. data/app/solid_agents/prompts/alex/instructions.txt.erb +3 -0
  21. data/app/solid_agents/prompts/betty/instructions.txt.erb +3 -0
  22. data/app/solid_agents/prompts/chad/instructions.txt.erb +3 -0
  23. data/app/solid_agents/prompts/david/instructions.txt.erb +3 -0
  24. data/app/solid_agents/prompts/eddy/instructions.txt.erb +3 -0
  25. data/app/tools/solid_agents/tools/workflow_guide_tool.rb +21 -0
  26. data/app/views/solid_agents/agents/edit.html.erb +4 -7
  27. data/app/views/solid_agents/runs/index.html.erb +4 -2
  28. data/app/views/solid_agents/runs/show.html.erb +7 -0
  29. data/lib/generators/solid_agents/install/install_generator.rb +2 -1
  30. data/lib/generators/solid_agents/install/templates/config/initializers/solid_agents.rb +6 -2
  31. data/lib/generators/solid_agents/install/templates/db/agent_schema.rb +30 -3
  32. data/lib/solid_agents/engine.rb +11 -0
  33. data/lib/solid_agents/runtime/ruby_llm_adapter.rb +20 -0
  34. data/lib/solid_agents/version.rb +1 -1
  35. data/lib/solid_agents/workflow.rb +48 -0
  36. data/lib/solid_agents.rb +12 -8
  37. metadata +62 -5
  38. data/lib/solid_agents/runtime/openclaw_adapter.rb +0 -12
  39. data/lib/solid_agents/runtime/tinyclaw_adapter.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f47eb3e38b46a127496f51a08a4a9613becb2abc109922b1ad4f5f2b203c89a2
4
- data.tar.gz: ad064cee60b057a8eb9dc3baccf5f06c48411550f91f984a35ff8a32fca51d5e
3
+ metadata.gz: e4096d5a7518890d89a9ab5ef5583e1828f9457abe69f536c2e7042c05e9288a
4
+ data.tar.gz: f466a2d473053692596c5c70f43530df1e77e474c10622084ef6f3431d4b36b3
5
5
  SHA512:
6
- metadata.gz: fd4fe012fb44f5f2707152fae422cbc0a4a63b2342e3fac2e485231808d46c460c8465642fa747f37e7aa14820763f8a1bc9a722c65e1734b76db14c1153892f
7
- data.tar.gz: 31a7f4a1ecc53a08710c656b7c7009d118e01de305f273d112984d460e1a826a0f5b4c14edbe5833bcb4589ffd1b6fa620346b8b23f61b52f265c3afd49eaf4b
6
+ metadata.gz: c1833f9334bf37f89c13d473154ef428240b87772fbedac727daa369f6cda15906ab93225fee8c3471f0d523794a5e9efa489d2e8c443f8e097518c12c23535d
7
+ data.tar.gz: 887265f38a7cdb95a05f15ab8a0919af5d1e9039de54a2f01e2507fecd75c6aa53cc5c52acf983f715c885950c2b158323a4969f4e3b9f962eea0245132301cd
data/CHANGELOG.md CHANGED
@@ -2,13 +2,44 @@
2
2
 
3
3
  All notable changes to `solid_agents` will be documented in this file.
4
4
 
5
+ ## [v0.2.1] - 2026-03-23
6
+
7
+ Follow-up release for RubyLLM runtime and path conventions.
8
+
9
+ - Moved agent classes and prompt templates to `app/solid_agents/agents` and `app/solid_agents/prompts`.
10
+ - Added VCR-backed live RubyLLM integration coverage with secret filtering and record-once behavior.
11
+ - Standardized LLM credential loading to environment variables only and added `.env.sample`.
12
+ - Updated installer and docs to reflect ENV-first configuration and current runtime defaults.
13
+
14
+ Status notes:
15
+
16
+ - This release is still WIP and not production-ready.
17
+ - Breaking changes are expected before `1.0`.
18
+
19
+ ## [v0.2.0] - 2026-03-23
20
+
21
+ Major architecture reset delivered as a minor release for rapid iteration.
22
+
23
+ - Replaced runtime adapters with a single RubyLLM-first execution path.
24
+ - Rebuilt the run model into an event-driven staged workflow.
25
+ - Added work-item board tracking and explicit inter-agent handoff records.
26
+ - Introduced stage ownership with alphabetical agents: alex, betty, chad, david, eddy.
27
+ - Updated installer schema and initializer templates for the new workflow primitives.
28
+ - Reworked run UI to expose stage, owner, events, and artifacts in clean columns.
29
+ - Expanded Minitest coverage and moved to YAML fixtures for deterministic test data.
30
+
31
+ Status notes:
32
+
33
+ - This release is still WIP and not production-ready.
34
+ - Breaking changes are expected before `1.0`.
35
+
5
36
  ## [v0.1.0] - 2026-03-22
6
37
 
7
38
  Initial public release (WIP).
8
39
 
9
40
  - Introduced `solid_agents` Rails engine for database-backed agent run orchestration.
10
41
  - Added run lifecycle models and persistence for runs, events, artifacts, agents, and config.
11
- - Added dispatch and execution flow with runtime adapters for TinyClaw and OpenClaw.
42
+ - Added dispatch and execution flow with runtime adapters for OpenAI RubyLLM runtime and OpenAI RubyLLM runtime.
12
43
  - Added built-in UI/controllers for managing agents and inspecting runs.
13
44
  - Added installer generator, schema template, and base configuration defaults.
14
45
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SolidAgents
2
2
 
3
- **Automation workflows for Rails apps, powered by agent runtimes.**
3
+ **Event-driven error fixing workflow for Rails apps, powered by RubyLLM agents.**
4
4
 
5
5
  > [!WARNING]
6
6
  > `solid_agents` is an early release and still a work in progress.
@@ -8,26 +8,30 @@
8
8
  > Expect breaking changes before `1.0`.
9
9
  > Not production-ready yet.
10
10
 
11
- `solid_agents` is a Rails engine that consumes observability/incident APIs (for example from `solid_events`), stores automation run state, dispatches work to runtime executors (TinyClaw in development, OpenClaw in production), and provides a built-in dashboard for operations.
11
+ `solid_agents` is a Rails engine focused on a single pipeline:
12
+
13
+ `error received -> staged agent workflow -> code fix attempt -> PR/CI stage tracking`
12
14
 
13
15
  ## Scope
14
16
 
15
- `solid_agents` is strictly for automation and execution:
17
+ `solid_agents` is for automation orchestration and execution only:
16
18
 
17
- - Consume incident/trace APIs and operator instructions
18
- - Plan/execute workflows (triage, patch, test, PR, QA, review loops)
19
- - Track run lifecycle, artifacts, and runtime outputs
20
- - Route tasks to runtime adapters (TinyClaw/OpenClaw)
19
+ - Consume error-like events from source adapters (starting with `solid_errors` style payloads)
20
+ - Track runs in an event-driven stage machine
21
+ - Enforce non-overlapping stage ownership (`alex`, `betty`, `chad`, `david`, `eddy`)
22
+ - Persist handoffs, notes, and artifacts for each stage
23
+ - Execute stage tasks through the RubyLLM runtime adapter
21
24
 
22
- It does **not** own observability storage or incident detection/state as a source of truth. That belongs in `solid_events`.
25
+ It does **not** own observability storage or incident detection as a source of truth.
23
26
 
24
27
  ## Features
25
28
 
26
- - DB-backed run lifecycle (`queued`, `running`, `succeeded`, `failed`)
27
- - Separate agent profiles per environment
28
- - Runtime adapters for TinyClaw and OpenClaw
29
- - Built-in UI for runs, events, artifacts, and agent configuration
30
- - Install generator and schema template aligned with Solid gem conventions
29
+ - DB-backed run lifecycle and stage workflow
30
+ - Append-only run events with actor attribution
31
+ - Work-item board columns driven by stage transitions
32
+ - Handoff records between stage owners
33
+ - Built-in UI for runs, events, and artifacts
34
+ - Installer generator and schema template
31
35
 
32
36
  ## Installation
33
37
 
@@ -43,25 +47,12 @@ Run installer:
43
47
  rails generate solid_agents:install
44
48
  ```
45
49
 
46
- Add a dedicated database in `config/database.yml` (recommended):
47
-
48
- ```yaml
49
- production:
50
- primary: &primary
51
- <<: *default
52
- database: app_production
53
- solid_agents:
54
- <<: *primary
55
- database: app_production_solid_agents
56
- migrations_paths: db/agent_migrate
57
- ```
58
-
59
- Configure engine DB connection:
50
+ Configure engine DB connection if desired:
60
51
 
61
52
  ```ruby
62
53
  # config/environments/production.rb
63
54
  config.solid_agents.connects_to = { database: { writing: :solid_agents } }
64
- config.solid_agents.default_runtime = :openclaw
55
+ config.solid_agents.default_runtime = :ruby_llm
65
56
  ```
66
57
 
67
58
  Mount the UI:
@@ -75,30 +66,36 @@ end
75
66
 
76
67
  ## Usage
77
68
 
78
- Create an agent profile:
69
+ Create pipeline agents:
79
70
 
80
71
  ```ruby
81
- SolidAgents::Agent.create!(
82
- key: "fixer",
83
- name: "Bug Fixer",
84
- role: "fixer",
85
- runtime: Rails.env.production? ? "openclaw" : "tinyclaw",
86
- working_directory: Rails.root.to_s,
87
- capabilities_json: {"allow_pr" => Rails.env.production?}
88
- )
72
+ %w[alex betty chad david eddy].each do |key|
73
+ SolidAgents::Agent.find_or_create_by!(key: key, environment: Rails.env) do |agent|
74
+ agent.name = key.capitalize
75
+ agent.role = key
76
+ agent.runtime = "ruby_llm"
77
+ agent.working_directory = Rails.root.to_s
78
+ agent.enabled = true
79
+ end
80
+ end
89
81
  ```
90
82
 
91
83
  Dispatch from a job:
92
84
 
93
85
  ```ruby
94
- SolidAgents.dispatch_error(source: solid_error_record, agent_key: "fixer")
86
+ SolidAgents.dispatch_error(source: solid_error_record, agent_key: "alex")
95
87
  ```
96
88
 
89
+ ## RubyLLM Conventions
90
+
91
+ - Agent classes live in `app/solid_agents/agents`.
92
+ - Prompt instructions live in `app/solid_agents/prompts/.../instructions.txt.erb`.
93
+ - Stage owners map directly to RubyLLM agent classes.
94
+
97
95
  ## Configuration
98
96
 
99
97
  ```ruby
100
- config.solid_agents.tinyclaw_command = "tinyclaw"
101
- config.solid_agents.openclaw_command = "openclaw"
98
+ config.solid_agents.default_model = "minimax/minimax-m2.7"
102
99
  config.solid_agents.default_test_command = "bin/rails test"
103
100
  config.solid_agents.max_iterations = 8
104
101
  ```
@@ -108,4 +105,19 @@ config.solid_agents.max_iterations = 8
108
105
  ```bash
109
106
  bundle install
110
107
  bundle exec rake test
108
+ gem build solid_agents.gemspec
111
109
  ```
110
+
111
+ ## Secrets And Testing
112
+
113
+ - Runtime credentials are loaded from environment variables only: `OPENROUTER_API_KEY` and optional `OPENROUTER_API_BASE`.
114
+ - Keep real keys out of committed files and never commit `.env`.
115
+ - Live LLM tests use VCR with `record: :once` and secret filtering.
116
+ - Record cassettes intentionally with:
117
+
118
+ ```bash
119
+ LIVE_LLM=1 OPENROUTER_API_KEY=... bundle exec rake test TEST=test/integration/solid_agents/ruby_llm_live_flow_test.rb
120
+ ```
121
+
122
+ - To re-record a live interaction, delete the cassette file first and run the command again.
123
+ - You can create a local `.env` from `.env.sample` and load it with `set -a; source .env; set +a`.
@@ -17,13 +17,16 @@ module SolidAgents
17
17
  def retry
18
18
  duplicated = @run.dup
19
19
  duplicated.status = :queued
20
+ duplicated.stage = "received"
21
+ duplicated.stage_owner = "alex"
20
22
  duplicated.started_at = nil
21
23
  duplicated.finished_at = nil
22
24
  duplicated.error_payload = nil
23
25
  duplicated.result_payload = nil
24
26
  duplicated.external_key = "retry-#{@run.id}-#{Time.current.to_i}"
25
27
  duplicated.save!
26
- duplicated.append_event!("retried", message: "Run created from retry", payload: {original_run_id: @run.id})
28
+ duplicated.create_work_item!(column_key: duplicated.stage, title: @run.work_item&.title || "Retry ##{@run.id}", summary: "Retry workflow run", metadata_json: {"original_run_id" => @run.id})
29
+ duplicated.append_event!("retried", message: "Run created from retry", payload: {"original_run_id" => @run.id}, actor: "alex")
27
30
  SolidAgents::ExecuteRunJob.perform_later(duplicated.id)
28
31
 
29
32
  redirect_to run_path(duplicated), notice: "Run retried."
@@ -6,6 +6,8 @@ module SolidAgents
6
6
 
7
7
  def perform(run_id)
8
8
  run = SolidAgents::Run.find(run_id)
9
+ return if SolidAgents::Workflow.final_stage?(run.stage) || run.failed? || run.succeeded?
10
+
9
11
  SolidAgents::Runs::Executor.call(run)
10
12
  end
11
13
  end
@@ -4,7 +4,7 @@ module SolidAgents
4
4
  class Agent < Record
5
5
  self.table_name = "solid_agents_agents"
6
6
 
7
- ROLES = %w[fixer reviewer qa custom].freeze
7
+ ROLES = %w[alex betty chad david eddy].freeze
8
8
 
9
9
  has_many :runs, class_name: "SolidAgents::Run", dependent: :nullify
10
10
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ class Handoff < Record
5
+ self.table_name = "solid_agents_handoffs"
6
+
7
+ belongs_to :run, class_name: "SolidAgents::Run"
8
+
9
+ validates :from_agent, :to_agent, :stage, presence: true
10
+ end
11
+ end
@@ -7,6 +7,7 @@ module SolidAgents
7
7
  STATUSES = {
8
8
  queued: "queued",
9
9
  running: "running",
10
+ blocked: "blocked",
10
11
  pr_opened: "pr_opened",
11
12
  succeeded: "succeeded",
12
13
  failed: "failed",
@@ -16,23 +17,57 @@ module SolidAgents
16
17
  belongs_to :agent, class_name: "SolidAgents::Agent"
17
18
  has_many :events, class_name: "SolidAgents::RunEvent", foreign_key: :run_id, dependent: :delete_all
18
19
  has_many :artifacts, class_name: "SolidAgents::Artifact", foreign_key: :run_id, dependent: :delete_all
20
+ has_many :handoffs, class_name: "SolidAgents::Handoff", foreign_key: :run_id, dependent: :delete_all
21
+ has_one :work_item, class_name: "SolidAgents::WorkItem", foreign_key: :run_id, dependent: :delete
19
22
 
20
23
  enum :status, STATUSES
21
24
 
22
- validates :runtime, :environment, :status, :source_type, presence: true
25
+ validates :runtime, :environment, :status, :source_type, :stage, presence: true
23
26
  validates :external_key, uniqueness: true, allow_nil: true
24
27
 
25
28
  before_validation :set_defaults, on: :create
26
29
 
27
- def append_event!(event_type, message:, payload: nil)
30
+ def append_event!(event_type, message:, payload: nil, actor: nil)
28
31
  next_sequence = (events.maximum(:sequence) || 0) + 1
29
- events.create!(event_type: event_type, message: message, payload: payload || {}, event_time: Time.current, sequence: next_sequence)
32
+ events.create!(
33
+ event_type: event_type,
34
+ message: message,
35
+ payload: payload || {},
36
+ actor: actor || stage_owner,
37
+ event_time: Time.current,
38
+ sequence: next_sequence
39
+ )
40
+ end
41
+
42
+ def transition_to!(next_stage, actor:, message:, payload: {})
43
+ update!(stage: next_stage, stage_owner: SolidAgents::Workflow.stage_agent(next_stage))
44
+ work_item&.update!(column_key: next_stage)
45
+ append_event!("stage_transitioned", message: message, payload: payload.merge("next_stage" => next_stage), actor: actor)
46
+ end
47
+
48
+ def start_stage!(actor:)
49
+ update!(status: :running, started_at: (started_at || Time.current))
50
+ append_event!("stage_started", message: "Stage #{stage} started", payload: {"stage" => stage}, actor: actor)
51
+ end
52
+
53
+ def complete!(result_payload:, actor:)
54
+ update!(status: :succeeded, stage: "done", stage_owner: SolidAgents::Workflow.stage_agent("done"), finished_at: Time.current, result_payload: result_payload)
55
+ work_item&.update!(column_key: "done")
56
+ append_event!("run_completed", message: "Run completed successfully", payload: result_payload, actor: actor)
57
+ end
58
+
59
+ def fail!(error_payload:, actor:)
60
+ update!(status: :failed, finished_at: Time.current, error_payload: error_payload)
61
+ work_item&.update!(column_key: "failed")
62
+ append_event!("run_failed", message: "Run failed", payload: error_payload, actor: actor)
30
63
  end
31
64
 
32
65
  private
33
66
 
34
67
  def set_defaults
35
68
  self.status ||= :queued
69
+ self.stage ||= "received"
70
+ self.stage_owner ||= SolidAgents::Workflow.stage_agent(stage)
36
71
  self.runtime ||= agent&.runtime || SolidAgents.default_runtime.to_s
37
72
  self.environment ||= Rails.env
38
73
  self.test_command ||= SolidAgents.default_test_command
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ class WorkItem < Record
5
+ self.table_name = "solid_agents_work_items"
6
+
7
+ belongs_to :run, class_name: "SolidAgents::Run"
8
+
9
+ validates :column_key, :title, presence: true
10
+ end
11
+ end
@@ -16,12 +16,15 @@ module SolidAgents
16
16
  external_key: "#{source.class.name}-#{source.respond_to?(:id) ? source.id : source.object_id}-#{Time.current.to_i}",
17
17
  repo_path: agent.working_directory,
18
18
  base_branch: "main",
19
- max_iterations: agent.max_iterations
19
+ max_iterations: agent.max_iterations,
20
+ stage: "received",
21
+ stage_owner: "alex"
20
22
  )
21
23
 
22
24
  context = ContextBuilder.call(source: source)
23
25
  run.update!(prompt_payload: context)
24
- run.append_event!("dispatched", message: "Run dispatched from source", payload: {agent_key: agent.key})
26
+ run.append_event!("run_received", message: "Run received from source", payload: {"agent_key" => agent.key, "source_type" => run.source_type}, actor: "alex")
27
+ run.create_work_item!(column_key: run.stage, title: "Fix #{run.source_type}##{run.source_id || "n/a"}", summary: "Automated error-fixing pipeline", metadata_json: {"agent_key" => agent.key})
25
28
 
26
29
  SolidAgents::ExecuteRunJob.perform_later(run.id)
27
30
  run
@@ -4,24 +4,56 @@ module SolidAgents
4
4
  module Runs
5
5
  class Executor
6
6
  def self.call(run)
7
- run.update!(status: :running, started_at: Time.current)
8
- run.append_event!("runtime_started", message: "Runtime execution started")
7
+ stage = run.stage
8
+ owner = SolidAgents::Workflow.stage_agent(stage)
9
+
10
+ run.start_stage!(actor: owner)
9
11
 
10
12
  prompt = PromptBuilder.call(run: run, context: run.prompt_payload || {})
11
13
  adapter = SolidAgents.runtime_adapter(run.runtime)
12
14
  result = adapter.execute(run: run, prompt: prompt)
13
15
 
14
- run.artifacts.create!(kind: "log", label: "runtime_output", storage_type: "inline", content_text: result.output.to_s)
16
+ run.artifacts.create!(
17
+ kind: "log",
18
+ label: "#{stage}_runtime_output",
19
+ storage_type: "inline",
20
+ content_text: result.output.to_s,
21
+ content_json: {"metadata" => result.metadata.to_h}
22
+ )
23
+
24
+ unless result.ok
25
+ run.fail!(error_payload: {"stage" => stage, "stderr" => result.error.to_s, "metadata" => result.metadata.to_h}, actor: owner)
26
+ return run
27
+ end
28
+
29
+ next_stage = SolidAgents::Workflow.next_stage(stage)
30
+ next_owner = SolidAgents::Workflow.stage_agent(next_stage)
15
31
 
16
- if result.ok
17
- metadata = result.metadata.to_h
18
- run.update!(status: :succeeded, finished_at: Time.current, result_payload: {output: result.output, metadata: metadata})
19
- run.append_event!("runtime_succeeded", message: "Runtime execution finished", payload: metadata)
32
+ run.handoffs.create!(
33
+ stage: stage,
34
+ from_agent: owner,
35
+ to_agent: next_owner,
36
+ note: "#{owner} completed #{stage} and handed off to #{next_owner}",
37
+ payload: {"output_excerpt" => result.output.to_s.slice(0, 500)}
38
+ )
39
+
40
+ run.append_event!(
41
+ "stage_completed",
42
+ message: "#{owner} completed #{stage}",
43
+ payload: {"stage" => stage, "next_stage" => next_stage, "next_owner" => next_owner},
44
+ actor: owner
45
+ )
46
+
47
+ if next_stage == "done"
48
+ run.complete!(result_payload: {"final_stage" => stage, "metadata" => result.metadata.to_h, "output" => result.output.to_s}, actor: next_owner)
20
49
  else
21
- run.update!(status: :failed, finished_at: Time.current, error_payload: {stderr: result.error, metadata: result.metadata})
22
- run.append_event!("runtime_failed", message: "Runtime execution failed", payload: result.metadata.to_h.merge("stderr" => result.error.to_s))
50
+ run.transition_to!(next_stage, actor: owner, message: "Transitioned from #{stage} to #{next_stage}", payload: {"next_owner" => next_owner})
51
+ SolidAgents::ExecuteRunJob.perform_later(run.id)
23
52
  end
24
53
 
54
+ run
55
+ rescue StandardError => e
56
+ run.fail!(error_payload: {"stage" => run.stage, "exception" => e.class.name, "message" => e.message}, actor: SolidAgents::Workflow.stage_agent(run.stage))
25
57
  run
26
58
  end
27
59
  end
@@ -7,25 +7,19 @@ module SolidAgents
7
7
  class PromptBuilder
8
8
  def self.call(run:, context:)
9
9
  <<~PROMPT
10
- You are #{run.agent.name} (#{run.agent.role}).
11
- Goal: fix the reported Rails issue end-to-end.
10
+ Stage owner: #{run.stage_owner}
11
+ Stage: #{run.stage}
12
+ Run id: #{run.id}
12
13
 
13
14
  Constraints:
14
- - Work in repository: #{run.repo_path}
15
+ - Repository path: #{run.repo_path}
15
16
  - Base branch: #{run.base_branch}
16
17
  - Test command: #{run.test_command}
18
+ - Runtime: #{run.runtime}
17
19
  - Max iterations: #{run.max_iterations || SolidAgents.max_iterations}
18
- - Open PR allowed: #{run.agent.capability?("allow_pr")}
19
20
 
20
21
  Context JSON:
21
22
  #{JSON.pretty_generate(context)}
22
-
23
- Definition of done:
24
- 1) Root cause identified.
25
- 2) Code fix applied.
26
- 3) Tests added or updated.
27
- 4) Tests executed and passing.
28
- 5) Return final JSON with keys: status, branch_name, test_summary, pr_url, notes.
29
23
  PROMPT
30
24
  end
31
25
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Agents
5
+ class Alex < Base
6
+ def initialize(run:, context:)
7
+ super(run: run, context: context, owner: "alex")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Agents
5
+ class Base < RubyLLM::Agent
6
+ model SolidAgents.default_model, provider: SolidAgents.default_provider
7
+ tools SolidAgents::Tools::WorkflowGuideTool.new
8
+
9
+ attr_reader :run, :context, :owner
10
+
11
+ def initialize(run:, context:, owner:)
12
+ @run = run
13
+ @context = context
14
+ @owner = owner.to_s
15
+ super()
16
+ end
17
+
18
+ def call(prompt)
19
+ ask(prompt)
20
+ end
21
+
22
+ def instructions
23
+ template_path = File.expand_path("../prompts/#{owner}/instructions.txt.erb", __dir__)
24
+ ERB.new(File.read(template_path)).result(binding)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Agents
5
+ class Betty < Base
6
+ def initialize(run:, context:)
7
+ super(run: run, context: context, owner: "betty")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Agents
5
+ class Chad < Base
6
+ def initialize(run:, context:)
7
+ super(run: run, context: context, owner: "chad")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Agents
5
+ class David < Base
6
+ def initialize(run:, context:)
7
+ super(run: run, context: context, owner: "david")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Agents
5
+ class Eddy < Base
6
+ def initialize(run:, context:)
7
+ super(run: run, context: context, owner: "eddy")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "agents/base"
4
+ require_relative "agents/alex"
5
+ require_relative "agents/betty"
6
+ require_relative "agents/chad"
7
+ require_relative "agents/david"
8
+ require_relative "agents/eddy"
9
+
10
+ module SolidAgents
11
+ module Agents
12
+ AGENT_CLASSES = {
13
+ "alex" => SolidAgents::Agents::Alex,
14
+ "betty" => SolidAgents::Agents::Betty,
15
+ "chad" => SolidAgents::Agents::Chad,
16
+ "david" => SolidAgents::Agents::David,
17
+ "eddy" => SolidAgents::Agents::Eddy
18
+ }.freeze
19
+
20
+ module_function
21
+
22
+ def for_owner(owner)
23
+ AGENT_CLASSES.fetch(owner.to_s, SolidAgents::Agents::Alex)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ You are Alex, the intake and triage agent for SolidAgents.
2
+ Work stage: <%= run.stage %>
3
+ Produce structured triage notes and a clean handoff summary for Betty.
@@ -0,0 +1,3 @@
1
+ You are Betty, the reproduction agent for SolidAgents.
2
+ Work stage: <%= run.stage %>
3
+ Prioritize failing automated reproduction and provide reproducible evidence.
@@ -0,0 +1,3 @@
1
+ You are Chad, the code fix implementation agent for SolidAgents.
2
+ Work stage: <%= run.stage %>
3
+ Apply minimal safe fixes and prepare concise rationale for David.
@@ -0,0 +1,3 @@
1
+ You are David, the verification agent for SolidAgents.
2
+ Work stage: <%= run.stage %>
3
+ Validate automated and manual verification evidence before handoff.
@@ -0,0 +1,3 @@
1
+ You are Eddy, the PR and CI shepherd agent for SolidAgents.
2
+ Work stage: <%= run.stage %>
3
+ Ensure PR quality, CI follow-through, and clear closure notes.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Tools
5
+ class WorkflowGuideTool < RubyLLM::Tool
6
+ description "Returns workflow guidance for a given stage owner pair"
7
+
8
+ param :stage, type: "string", desc: "Current workflow stage"
9
+ param :owner, type: "string", desc: "Current stage owner"
10
+
11
+ def execute(stage:, owner:)
12
+ {
13
+ stage: stage,
14
+ owner: owner,
15
+ guidance: "Produce concise evidence, then hand off cleanly to the next stage owner.",
16
+ required_outputs: ["notes", "artifacts", "handoff_summary"]
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,17 +1,14 @@
1
1
  <div class="card">
2
- <h2>Edit Agent <%= @agent.key %></h2>
3
-
2
+ <h2>Edit Agent</h2>
4
3
  <%= form_with model: @agent, url: agent_path(@agent), method: :patch do |f| %>
5
4
  <p><%= f.label :name %><br><%= f.text_field :name %></p>
6
5
  <p><%= f.label :role %><br><%= f.select :role, SolidAgents::Agent::ROLES %></p>
7
- <p><%= f.label :runtime %><br><%= f.select :runtime, %w[tinyclaw openclaw] %></p>
6
+ <p><%= f.label :runtime %><br><%= f.select :runtime, %w[pi] %></p>
8
7
  <p><%= f.label :environment %><br><%= f.text_field :environment %></p>
9
- <p><%= f.label :model %><br><%= f.text_field :model %></p>
10
8
  <p><%= f.label :working_directory %><br><%= f.text_field :working_directory %></p>
11
9
  <p><%= f.label :timeout_seconds %><br><%= f.number_field :timeout_seconds %></p>
12
10
  <p><%= f.label :max_iterations %><br><%= f.number_field :max_iterations %></p>
13
- <p><%= f.label :system_prompt %><br><%= f.text_area :system_prompt, rows: 8, cols: 80 %></p>
14
- <p><%= f.label :enabled %> <%= f.check_box :enabled %></p>
15
- <p><%= f.submit "Save", class: "btn primary" %></p>
11
+ <p><%= f.label :enabled %><br><%= f.check_box :enabled %></p>
12
+ <%= f.submit "Save", class: "btn primary" %>
16
13
  <% end %>
17
14
  </div>
@@ -6,9 +6,10 @@
6
6
  <th>ID</th>
7
7
  <th>Agent</th>
8
8
  <th>Status</th>
9
+ <th>Stage</th>
10
+ <th>Owner</th>
9
11
  <th>Runtime</th>
10
12
  <th>Source</th>
11
- <th>Started</th>
12
13
  </tr>
13
14
  </thead>
14
15
  <tbody>
@@ -17,9 +18,10 @@
17
18
  <td><%= link_to "##{run.id}", run_path(run) %></td>
18
19
  <td><%= run.agent&.key %></td>
19
20
  <td><span class="badge <%= status_badge_class(run.status) %>"><%= run.status %></span></td>
21
+ <td><%= run.stage %></td>
22
+ <td><%= run.stage_owner %></td>
20
23
  <td><%= run.runtime %></td>
21
24
  <td><%= [run.source_type, run.source_id].compact.join("#") %></td>
22
- <td><%= run.started_at || run.created_at %></td>
23
25
  </tr>
24
26
  <% end %>
25
27
  </tbody>
@@ -5,6 +5,11 @@
5
5
  Runtime: <strong><%= @run.runtime %></strong> |
6
6
  Status: <span class="badge <%= status_badge_class(@run.status) %>"><%= @run.status %></span>
7
7
  </p>
8
+ <p>
9
+ Stage: <strong><%= @run.stage %></strong> |
10
+ Owner: <strong><%= @run.stage_owner %></strong> |
11
+ Board Column: <strong><%= @run.work_item&.column_key || @run.stage %></strong>
12
+ </p>
8
13
  <p>
9
14
  Source: <%= [@run.source_type, @run.source_id].compact.join("#") %>
10
15
  </p>
@@ -19,6 +24,7 @@
19
24
  <tr>
20
25
  <th>#</th>
21
26
  <th>Type</th>
27
+ <th>Actor</th>
22
28
  <th>Message</th>
23
29
  </tr>
24
30
  </thead>
@@ -27,6 +33,7 @@
27
33
  <tr>
28
34
  <td><%= event.sequence %></td>
29
35
  <td><%= event.event_type %></td>
36
+ <td><%= event.actor %></td>
30
37
  <td><%= event.message %></td>
31
38
  </tr>
32
39
  <% end %>
@@ -18,7 +18,8 @@ module SolidAgents
18
18
  "",
19
19
  '\\1# Configure Solid Agent',
20
20
  '\\1config.solid_agents.connects_to = { database: { writing: :solid_agents } }',
21
- '\\1config.solid_agents.default_runtime = :openclaw'
21
+ '\\1config.solid_agents.default_runtime = :ruby_llm',
22
+ '\\1config.solid_agents.default_provider = :openrouter'
22
23
  ].join("\n")
23
24
  end
24
25
  end
@@ -4,8 +4,12 @@ Rails.application.configure do
4
4
  # Optional: override in specific environments.
5
5
  # config.solid_agents.connects_to = { database: { writing: :solid_agents } }
6
6
 
7
- config.solid_agents.tinyclaw_command = ENV.fetch("SOLID_AGENTS_TINYCLAW_COMMAND", "tinyclaw")
8
- config.solid_agents.openclaw_command = ENV.fetch("SOLID_AGENTS_OPENCLAW_COMMAND", "openclaw")
7
+ # Configure LLM access with environment variables:
8
+ # OPENROUTER_API_KEY="..."
9
+ # OPENROUTER_API_BASE="https://openrouter.ai/api/v1" # optional
10
+
11
+ config.solid_agents.default_model = ENV.fetch("SOLID_AGENTS_DEFAULT_MODEL", "minimax/minimax-m2.7")
12
+ config.solid_agents.default_provider = :openrouter
9
13
  config.solid_agents.default_test_command = ENV.fetch("SOLID_AGENTS_TEST_COMMAND", "bin/rails test")
10
14
  config.solid_agents.max_iterations = ENV.fetch("SOLID_AGENTS_MAX_ITERATIONS", 8).to_i
11
15
  end
@@ -4,8 +4,8 @@ ActiveRecord::Schema[6.1].define do
4
4
  create_table :solid_agents_agents, force: :cascade do |t|
5
5
  t.string :key, null: false
6
6
  t.string :name, null: false
7
- t.string :role, null: false, default: "fixer"
8
- t.string :runtime, null: false, default: "tinyclaw"
7
+ t.string :role, null: false, default: "alex"
8
+ t.string :runtime, null: false, default: "ruby_llm"
9
9
  t.boolean :enabled, null: false, default: true
10
10
  t.string :environment
11
11
  t.string :model
@@ -26,7 +26,9 @@ ActiveRecord::Schema[6.1].define do
26
26
  t.bigint :source_id
27
27
  t.string :error_fingerprint
28
28
  t.string :status, null: false, default: "queued"
29
- t.string :runtime, null: false
29
+ t.string :stage, null: false, default: "received"
30
+ t.string :stage_owner, null: false, default: "alex"
31
+ t.string :runtime, null: false, default: "ruby_llm"
30
32
  t.string :environment, null: false
31
33
  t.string :repo_path
32
34
  t.string :base_branch
@@ -47,14 +49,39 @@ ActiveRecord::Schema[6.1].define do
47
49
 
48
50
  add_index :solid_agents_runs, :external_key, unique: true
49
51
  add_index :solid_agents_runs, :status
52
+ add_index :solid_agents_runs, :stage
50
53
  add_index :solid_agents_runs, :error_fingerprint
51
54
  add_index :solid_agents_runs, [:source_type, :source_id]
52
55
 
56
+ create_table :solid_agents_work_items, force: :cascade do |t|
57
+ t.references :run, null: false, foreign_key: {to_table: :solid_agents_runs}
58
+ t.string :column_key, null: false, default: "received"
59
+ t.string :title, null: false
60
+ t.text :summary
61
+ t.json :metadata_json, default: {}
62
+ t.timestamps
63
+ end
64
+
65
+ add_index :solid_agents_work_items, :column_key
66
+
67
+ create_table :solid_agents_handoffs, force: :cascade do |t|
68
+ t.references :run, null: false, foreign_key: {to_table: :solid_agents_runs}
69
+ t.string :stage, null: false
70
+ t.string :from_agent, null: false
71
+ t.string :to_agent, null: false
72
+ t.text :note
73
+ t.json :payload, default: {}
74
+ t.timestamps
75
+ end
76
+
77
+ add_index :solid_agents_handoffs, [:run_id, :stage]
78
+
53
79
  create_table :solid_agents_run_events, force: :cascade do |t|
54
80
  t.references :run, null: false, foreign_key: {to_table: :solid_agents_runs}
55
81
  t.string :event_type, null: false
56
82
  t.datetime :event_time, null: false
57
83
  t.text :message, null: false
84
+ t.string :actor
58
85
  t.json :payload, default: {}
59
86
  t.integer :sequence, null: false
60
87
  t.timestamps
@@ -4,6 +4,7 @@ module SolidAgents
4
4
  class Engine < ::Rails::Engine
5
5
  config.root = File.expand_path("../..", __dir__)
6
6
  isolate_namespace SolidAgents
7
+ paths.add "app/solid_agents", eager_load: true
7
8
 
8
9
  config.solid_agents = ActiveSupport::OrderedOptions.new
9
10
 
@@ -12,5 +13,15 @@ module SolidAgents
12
13
  SolidAgents.public_send(:"#{name}=", value)
13
14
  end
14
15
  end
16
+
17
+ initializer "solid_agents.ruby_llm" do
18
+ SolidAgents.openrouter_api_key ||= ENV["OPENROUTER_API_KEY"]
19
+ SolidAgents.openrouter_api_base ||= ENV["OPENROUTER_API_BASE"]
20
+
21
+ RubyLLM.configure do |config|
22
+ config.openrouter_api_key = SolidAgents.openrouter_api_key if SolidAgents.openrouter_api_key.present?
23
+ config.openrouter_api_base = SolidAgents.openrouter_api_base if SolidAgents.openrouter_api_base.present?
24
+ end
25
+ end
15
26
  end
16
27
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_llm"
4
+
5
+ module SolidAgents
6
+ module Runtime
7
+ class RubyLlmAdapter < Adapter
8
+ def execute(run:, prompt:)
9
+ agent_class = SolidAgents::Agents.for_owner(run.stage_owner)
10
+ agent = agent_class.new(run: run, context: run.prompt_payload || {})
11
+ response = agent.call(prompt)
12
+ output = response.respond_to?(:content) ? response.content.to_s : response.to_s
13
+
14
+ Result.new(ok: true, output: output, error: nil, metadata: {agent_class: agent_class.name, stage: run.stage, owner: run.stage_owner})
15
+ rescue StandardError => e
16
+ Result.new(ok: false, output: nil, error: e.message, metadata: {agent_class: agent_class&.name, stage: run.stage, owner: run.stage_owner, exception: e.class.name})
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidAgents
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidAgents
4
+ module Workflow
5
+ STAGES = [
6
+ "received",
7
+ "triaged",
8
+ "repro_test",
9
+ "repro_manual",
10
+ "fixing",
11
+ "verifying",
12
+ "pr_opened",
13
+ "ci_wait",
14
+ "done"
15
+ ].freeze
16
+
17
+ STAGE_TO_AGENT = {
18
+ "received" => "alex",
19
+ "triaged" => "alex",
20
+ "repro_test" => "betty",
21
+ "repro_manual" => "betty",
22
+ "fixing" => "chad",
23
+ "verifying" => "david",
24
+ "pr_opened" => "eddy",
25
+ "ci_wait" => "eddy",
26
+ "done" => "eddy"
27
+ }.freeze
28
+
29
+ FINAL_STAGES = ["done", "failed"].freeze
30
+
31
+ module_function
32
+
33
+ def next_stage(current_stage)
34
+ index = STAGES.index(current_stage)
35
+ return "done" if index.nil? || index == STAGES.length - 1
36
+
37
+ STAGES[index + 1]
38
+ end
39
+
40
+ def stage_agent(stage)
41
+ STAGE_TO_AGENT.fetch(stage.to_s, "alex")
42
+ end
43
+
44
+ def final_stage?(stage)
45
+ FINAL_STAGES.include?(stage.to_s)
46
+ end
47
+ end
48
+ end
data/lib/solid_agents.rb CHANGED
@@ -1,32 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "solid_agents/version"
4
+ require_relative "solid_agents/workflow"
4
5
  require_relative "solid_agents/runtime/adapter"
5
- require_relative "solid_agents/runtime/tinyclaw_adapter"
6
- require_relative "solid_agents/runtime/openclaw_adapter"
6
+ require_relative "solid_agents/runtime/ruby_llm_adapter"
7
7
  require_relative "solid_agents/engine"
8
8
 
9
9
  module SolidAgents
10
10
  mattr_accessor :connects_to
11
11
  mattr_accessor :base_controller_class, default: "::ActionController::Base"
12
- mattr_accessor :default_runtime, default: :tinyclaw
13
- mattr_accessor :tinyclaw_command, default: "tinyclaw"
14
- mattr_accessor :openclaw_command, default: "openclaw"
12
+ mattr_accessor :default_runtime, default: :ruby_llm
13
+ mattr_accessor :default_model, default: "minimax/minimax-m2.7"
14
+ mattr_accessor :default_provider, default: :openrouter
15
+ mattr_accessor :openrouter_api_key
16
+ mattr_accessor :openrouter_api_base
15
17
  mattr_accessor :default_test_command, default: "bin/rails test"
16
18
  mattr_accessor :max_iterations, default: 8
17
19
 
18
20
  class << self
19
21
  def runtime_adapter(runtime)
20
22
  case runtime.to_sym
21
- when :tinyclaw then SolidAgents::Runtime::TinyclawAdapter.new
22
- when :openclaw then SolidAgents::Runtime::OpenclawAdapter.new
23
+ when :ruby_llm then SolidAgents::Runtime::RubyLlmAdapter.new
23
24
  else
24
25
  raise ArgumentError, "Unsupported runtime: #{runtime.inspect}"
25
26
  end
26
27
  end
27
28
 
28
- def dispatch_error(source:, agent_key: "fixer")
29
+ def dispatch_error(source:, agent_key: "alex")
29
30
  SolidAgents::Runs::Dispatch.call(source: source, agent_key: agent_key)
30
31
  end
31
32
  end
32
33
  end
34
+
35
+ require_relative "../app/tools/solid_agents/tools/workflow_guide_tool"
36
+ require_relative "../app/solid_agents/agents"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_agents
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto
@@ -93,6 +93,20 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '6.1'
96
+ - !ruby/object:Gem::Dependency
97
+ name: ruby_llm
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '1.0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
96
110
  - !ruby/object:Gem::Dependency
97
111
  name: sqlite3
98
112
  requirement: !ruby/object:Gem::Requirement
@@ -107,8 +121,36 @@ dependencies:
107
121
  - - ">="
108
122
  - !ruby/object:Gem::Version
109
123
  version: '2.0'
110
- description: Solid Agent stores agent runs in its own database and dispatches work
111
- to tinyclaw/openclaw runtimes with a built-in Rails UI.
124
+ - !ruby/object:Gem::Dependency
125
+ name: vcr
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '6.0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '6.0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: webmock
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '3.0'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '3.0'
152
+ description: Solid Agent stores agent runs in its own database and dispatches staged
153
+ workflow tasks to the RubyLLM runtime with a built-in Rails UI.
112
154
  email:
113
155
  - kr@kakaruto.com
114
156
  executables: []
@@ -127,13 +169,28 @@ files:
127
169
  - app/models/solid_agents/agent.rb
128
170
  - app/models/solid_agents/artifact.rb
129
171
  - app/models/solid_agents/config.rb
172
+ - app/models/solid_agents/handoff.rb
130
173
  - app/models/solid_agents/record.rb
131
174
  - app/models/solid_agents/run.rb
132
175
  - app/models/solid_agents/run_event.rb
176
+ - app/models/solid_agents/work_item.rb
133
177
  - app/services/solid_agents/runs/context_builder.rb
134
178
  - app/services/solid_agents/runs/dispatch.rb
135
179
  - app/services/solid_agents/runs/executor.rb
136
180
  - app/services/solid_agents/runs/prompt_builder.rb
181
+ - app/solid_agents/agents.rb
182
+ - app/solid_agents/agents/alex.rb
183
+ - app/solid_agents/agents/base.rb
184
+ - app/solid_agents/agents/betty.rb
185
+ - app/solid_agents/agents/chad.rb
186
+ - app/solid_agents/agents/david.rb
187
+ - app/solid_agents/agents/eddy.rb
188
+ - app/solid_agents/prompts/alex/instructions.txt.erb
189
+ - app/solid_agents/prompts/betty/instructions.txt.erb
190
+ - app/solid_agents/prompts/chad/instructions.txt.erb
191
+ - app/solid_agents/prompts/david/instructions.txt.erb
192
+ - app/solid_agents/prompts/eddy/instructions.txt.erb
193
+ - app/tools/solid_agents/tools/workflow_guide_tool.rb
137
194
  - app/views/layouts/solid_agents/_style.html.erb
138
195
  - app/views/layouts/solid_agents/application.html.erb
139
196
  - app/views/solid_agents/agents/edit.html.erb
@@ -150,9 +207,9 @@ files:
150
207
  - lib/solid_agents.rb
151
208
  - lib/solid_agents/engine.rb
152
209
  - lib/solid_agents/runtime/adapter.rb
153
- - lib/solid_agents/runtime/openclaw_adapter.rb
154
- - lib/solid_agents/runtime/tinyclaw_adapter.rb
210
+ - lib/solid_agents/runtime/ruby_llm_adapter.rb
155
211
  - lib/solid_agents/version.rb
212
+ - lib/solid_agents/workflow.rb
156
213
  homepage: https://github.com/kaka-ruto/solid_agents
157
214
  licenses:
158
215
  - MIT
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SolidAgents
4
- module Runtime
5
- class OpenclawAdapter < Adapter
6
- def execute(run:, prompt:)
7
- command = [SolidAgents.openclaw_command.to_s, "agent", "--message", prompt, "--thinking", "high"]
8
- run_command(*command)
9
- end
10
- end
11
- end
12
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SolidAgents
4
- module Runtime
5
- class TinyclawAdapter < Adapter
6
- def execute(run:, prompt:)
7
- command = [SolidAgents.tinyclaw_command.to_s, "send", "@#{run.agent.key} #{prompt}"]
8
- run_command(*command)
9
- end
10
- end
11
- end
12
- end