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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -1
- data/README.md +52 -40
- data/app/controllers/solid_agents/runs_controller.rb +4 -1
- data/app/jobs/solid_agents/execute_run_job.rb +2 -0
- data/app/models/solid_agents/agent.rb +1 -1
- data/app/models/solid_agents/handoff.rb +11 -0
- data/app/models/solid_agents/run.rb +38 -3
- data/app/models/solid_agents/work_item.rb +11 -0
- data/app/services/solid_agents/runs/dispatch.rb +5 -2
- data/app/services/solid_agents/runs/executor.rb +41 -9
- data/app/services/solid_agents/runs/prompt_builder.rb +5 -11
- data/app/solid_agents/agents/alex.rb +11 -0
- data/app/solid_agents/agents/base.rb +28 -0
- data/app/solid_agents/agents/betty.rb +11 -0
- data/app/solid_agents/agents/chad.rb +11 -0
- data/app/solid_agents/agents/david.rb +11 -0
- data/app/solid_agents/agents/eddy.rb +11 -0
- data/app/solid_agents/agents.rb +26 -0
- data/app/solid_agents/prompts/alex/instructions.txt.erb +3 -0
- data/app/solid_agents/prompts/betty/instructions.txt.erb +3 -0
- data/app/solid_agents/prompts/chad/instructions.txt.erb +3 -0
- data/app/solid_agents/prompts/david/instructions.txt.erb +3 -0
- data/app/solid_agents/prompts/eddy/instructions.txt.erb +3 -0
- data/app/tools/solid_agents/tools/workflow_guide_tool.rb +21 -0
- data/app/views/solid_agents/agents/edit.html.erb +4 -7
- data/app/views/solid_agents/runs/index.html.erb +4 -2
- data/app/views/solid_agents/runs/show.html.erb +7 -0
- data/lib/generators/solid_agents/install/install_generator.rb +2 -1
- data/lib/generators/solid_agents/install/templates/config/initializers/solid_agents.rb +6 -2
- data/lib/generators/solid_agents/install/templates/db/agent_schema.rb +30 -3
- data/lib/solid_agents/engine.rb +11 -0
- data/lib/solid_agents/runtime/ruby_llm_adapter.rb +20 -0
- data/lib/solid_agents/version.rb +1 -1
- data/lib/solid_agents/workflow.rb +48 -0
- data/lib/solid_agents.rb +12 -8
- metadata +62 -5
- data/lib/solid_agents/runtime/openclaw_adapter.rb +0 -12
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e4096d5a7518890d89a9ab5ef5583e1828f9457abe69f536c2e7042c05e9288a
|
|
4
|
+
data.tar.gz: f466a2d473053692596c5c70f43530df1e77e474c10622084ef6f3431d4b36b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
-
**
|
|
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
|
|
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
|
|
17
|
+
`solid_agents` is for automation orchestration and execution only:
|
|
16
18
|
|
|
17
|
-
- Consume
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
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
|
|
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
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
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
|
-
|
|
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 = :
|
|
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
|
|
69
|
+
Create pipeline agents:
|
|
79
70
|
|
|
80
71
|
```ruby
|
|
81
|
-
|
|
82
|
-
key:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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: "
|
|
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.
|
|
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.
|
|
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."
|
|
@@ -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!(
|
|
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
|
|
@@ -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!("
|
|
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
|
-
|
|
8
|
-
|
|
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!(
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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.
|
|
22
|
-
|
|
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
|
-
|
|
11
|
-
|
|
10
|
+
Stage owner: #{run.stage_owner}
|
|
11
|
+
Stage: #{run.stage}
|
|
12
|
+
Run id: #{run.id}
|
|
12
13
|
|
|
13
14
|
Constraints:
|
|
14
|
-
-
|
|
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,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,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,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
|
|
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[
|
|
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 :
|
|
14
|
-
|
|
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 = :
|
|
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
|
-
|
|
8
|
-
|
|
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: "
|
|
8
|
-
t.string :runtime, null: false, default: "
|
|
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 :
|
|
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
|
data/lib/solid_agents/engine.rb
CHANGED
|
@@ -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
|
data/lib/solid_agents/version.rb
CHANGED
|
@@ -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/
|
|
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: :
|
|
13
|
-
mattr_accessor :
|
|
14
|
-
mattr_accessor :
|
|
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 :
|
|
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: "
|
|
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
|
|
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
|
-
|
|
111
|
-
|
|
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/
|
|
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
|