rcrewai-rails 0.1.1 → 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/app/controllers/rcrewai/rails/agents_controller.rb +64 -0
- data/app/controllers/rcrewai/rails/api/v1/crews_controller.rb +55 -0
- data/app/controllers/rcrewai/rails/api/v1/executions_controller.rb +52 -0
- data/app/controllers/rcrewai/rails/crews_controller.rb +1 -1
- data/app/controllers/rcrewai/rails/executions_controller.rb +2 -2
- data/app/controllers/rcrewai/rails/tasks_controller.rb +76 -0
- data/app/controllers/rcrewai/rails/tools_controller.rb +61 -0
- data/app/models/rcrewai/rails/agent.rb +2 -2
- data/app/models/rcrewai/rails/task.rb +2 -6
- data/app/models/rcrewai/rails/tool.rb +26 -0
- data/app/views/rcrewai/rails/agents/edit.html.erb +107 -0
- data/app/views/rcrewai/rails/agents/index.html.erb +81 -0
- data/app/views/rcrewai/rails/agents/new.html.erb +103 -0
- data/app/views/rcrewai/rails/agents/show.html.erb +136 -0
- data/app/views/rcrewai/rails/crews/edit.html.erb +87 -0
- data/app/views/rcrewai/rails/crews/index.html.erb +1 -1
- data/app/views/rcrewai/rails/crews/new.html.erb +75 -0
- data/app/views/rcrewai/rails/executions/index.html.erb +91 -0
- data/app/views/rcrewai/rails/executions/show.html.erb +1 -1
- data/app/views/rcrewai/rails/tasks/edit.html.erb +105 -0
- data/app/views/rcrewai/rails/tasks/index.html.erb +82 -0
- data/app/views/rcrewai/rails/tasks/new.html.erb +101 -0
- data/app/views/rcrewai/rails/tasks/show.html.erb +129 -0
- data/app/views/rcrewai/rails/tools/edit.html.erb +60 -0
- data/app/views/rcrewai/rails/tools/index.html.erb +48 -0
- data/app/views/rcrewai/rails/tools/new.html.erb +56 -0
- data/app/views/rcrewai/rails/tools/show.html.erb +47 -0
- data/db/migrate/001_add_agent_to_tasks.rb +25 -0
- data/lib/rcrewai/rails/engine.rb +16 -10
- data/lib/rcrewai/rails/version.rb +1 -1
- data/rcrewai-rails.gemspec +20 -2
- metadata +41 -5
- /data/lib/{rcrewai-rails.rb → rcrewai_rails.rb} +0 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>
|
3
|
+
Tasks
|
4
|
+
<% if @crew %>
|
5
|
+
for <%= link_to @crew.name, @crew %>
|
6
|
+
<% end %>
|
7
|
+
</h1>
|
8
|
+
<div class="actions">
|
9
|
+
<%= link_to "New Task", new_task_path(@crew), class: "btn btn-primary" %>
|
10
|
+
<% if @crew %>
|
11
|
+
<%= link_to "Back to Crew", @crew, class: "btn" %>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<div class="tasks-list">
|
17
|
+
<% if @tasks.any? %>
|
18
|
+
<% @tasks.each do |task| %>
|
19
|
+
<div class="task-card">
|
20
|
+
<div class="task-header">
|
21
|
+
<h3><%= link_to "Task ##{task.id}", task %></h3>
|
22
|
+
<div class="task-meta">
|
23
|
+
<% if task.crew %>
|
24
|
+
<span class="badge">Crew: <%= link_to task.crew.name, task.crew %></span>
|
25
|
+
<% end %>
|
26
|
+
<% if task.agent %>
|
27
|
+
<span class="badge">Agent: <%= link_to task.agent.name, task.agent %></span>
|
28
|
+
<% end %>
|
29
|
+
<% if task.async_execution %>
|
30
|
+
<span class="badge badge-info">Async</span>
|
31
|
+
<% end %>
|
32
|
+
<% unless task.active %>
|
33
|
+
<span class="badge badge-warning">Inactive</span>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<div class="task-content">
|
39
|
+
<div class="task-description">
|
40
|
+
<strong>Description:</strong>
|
41
|
+
<p><%= truncate(task.description, length: 200) %></p>
|
42
|
+
</div>
|
43
|
+
|
44
|
+
<div class="task-output">
|
45
|
+
<strong>Expected Output:</strong>
|
46
|
+
<p><%= truncate(task.expected_output, length: 150) %></p>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<div class="task-dependencies">
|
51
|
+
<% if task.dependencies.any? %>
|
52
|
+
<strong>Dependencies:</strong>
|
53
|
+
<div class="dependency-list">
|
54
|
+
<% task.dependencies.each do |dep| %>
|
55
|
+
<span class="dependency-badge">
|
56
|
+
<%= link_to "Task ##{dep.id}", dep %>
|
57
|
+
</span>
|
58
|
+
<% end %>
|
59
|
+
</div>
|
60
|
+
<% end %>
|
61
|
+
</div>
|
62
|
+
|
63
|
+
<div class="task-actions">
|
64
|
+
<%= link_to "View", task, class: "btn btn-sm" %>
|
65
|
+
<%= link_to "Edit", edit_task_path(task), class: "btn btn-sm" %>
|
66
|
+
</div>
|
67
|
+
</div>
|
68
|
+
<% end %>
|
69
|
+
<% else %>
|
70
|
+
<div class="empty-state">
|
71
|
+
<h3>No tasks found</h3>
|
72
|
+
<p>
|
73
|
+
<% if @crew %>
|
74
|
+
This crew doesn't have any tasks yet.
|
75
|
+
<% else %>
|
76
|
+
No tasks have been created yet.
|
77
|
+
<% end %>
|
78
|
+
</p>
|
79
|
+
<%= link_to "Create First Task", new_task_path(@crew), class: "btn btn-primary" %>
|
80
|
+
</div>
|
81
|
+
<% end %>
|
82
|
+
</div>
|
@@ -0,0 +1,101 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>New Task</h1>
|
3
|
+
<div class="actions">
|
4
|
+
<% if @task.crew %>
|
5
|
+
<%= link_to "Back to Crew", @task.crew, class: "btn" %>
|
6
|
+
<% else %>
|
7
|
+
<%= link_to "All Tasks", tasks_path, class: "btn" %>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<div class="form-container">
|
13
|
+
<%= form_with model: [@crew, @task].compact, local: true do |form| %>
|
14
|
+
<% if @task.errors.any? %>
|
15
|
+
<div class="alert alert-error">
|
16
|
+
<h4><%= pluralize(@task.errors.count, "error") %> prohibited this task from being saved:</h4>
|
17
|
+
<ul>
|
18
|
+
<% @task.errors.full_messages.each do |message| %>
|
19
|
+
<li><%= message %></li>
|
20
|
+
<% end %>
|
21
|
+
</ul>
|
22
|
+
</div>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<div class="form-group">
|
26
|
+
<%= form.label :description, class: "form-label" %>
|
27
|
+
<%= form.text_area :description, class: "form-input", rows: 4, required: true %>
|
28
|
+
<span class="form-help">Detailed description of what this task should accomplish</span>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<div class="form-group">
|
32
|
+
<%= form.label :expected_output, class: "form-label" %>
|
33
|
+
<%= form.text_area :expected_output, class: "form-input", rows: 3, required: true %>
|
34
|
+
<span class="form-help">Description of the expected output from this task</span>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
<% unless @crew %>
|
38
|
+
<div class="form-group">
|
39
|
+
<%= form.label :crew_id, "Crew", class: "form-label" %>
|
40
|
+
<%= form.select :crew_id,
|
41
|
+
options_from_collection_for_select(RcrewAI::Rails::Crew.all, :id, :name, @task.crew_id),
|
42
|
+
{ prompt: 'Select a crew (optional)' },
|
43
|
+
{ class: "form-select" } %>
|
44
|
+
</div>
|
45
|
+
<% end %>
|
46
|
+
|
47
|
+
<div class="form-group">
|
48
|
+
<%= form.label :agent_id, "Assigned Agent", class: "form-label" %>
|
49
|
+
<% agents = @crew ? @crew.agents : RcrewAI::Rails::Agent.all %>
|
50
|
+
<%= form.select :agent_id,
|
51
|
+
options_from_collection_for_select(agents, :id, :name, @task.agent_id),
|
52
|
+
{ prompt: 'Select an agent' },
|
53
|
+
{ class: "form-select" } %>
|
54
|
+
</div>
|
55
|
+
|
56
|
+
<div class="form-group">
|
57
|
+
<%= form.label :async_execution, class: "form-label" %>
|
58
|
+
<%= form.check_box :async_execution, class: "form-checkbox" %>
|
59
|
+
<span class="form-help">Execute this task asynchronously</span>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div class="form-group">
|
63
|
+
<%= form.label :order_index, "Execution Order", class: "form-label" %>
|
64
|
+
<%= form.number_field :order_index, class: "form-input", min: 0 %>
|
65
|
+
<span class="form-help">Order in which this task should be executed (0 = first)</span>
|
66
|
+
</div>
|
67
|
+
|
68
|
+
<div class="form-group">
|
69
|
+
<%= form.label :output_file, class: "form-label" %>
|
70
|
+
<%= form.text_field :output_file, class: "form-input" %>
|
71
|
+
<span class="form-help">File path where output should be saved (optional)</span>
|
72
|
+
</div>
|
73
|
+
|
74
|
+
<div class="form-group">
|
75
|
+
<%= form.label :context, class: "form-label" %>
|
76
|
+
<%= form.text_area :context, class: "form-input", rows: 3 %>
|
77
|
+
<span class="form-help">Additional context for the task (optional)</span>
|
78
|
+
</div>
|
79
|
+
|
80
|
+
<div class="form-group">
|
81
|
+
<%= form.label :config, "Configuration (JSON)", class: "form-label" %>
|
82
|
+
<%= form.text_area :config, class: "form-input", rows: 3 %>
|
83
|
+
<span class="form-help">Task configuration in JSON format (optional)</span>
|
84
|
+
</div>
|
85
|
+
|
86
|
+
<div class="form-group">
|
87
|
+
<%= form.label :tools_config, "Tools Configuration (JSON)", class: "form-label" %>
|
88
|
+
<%= form.text_area :tools_config, class: "form-input", rows: 3 %>
|
89
|
+
<span class="form-help">Tools configuration in JSON format (optional)</span>
|
90
|
+
</div>
|
91
|
+
|
92
|
+
<div class="form-actions">
|
93
|
+
<%= form.submit "Create Task", class: "btn btn-primary" %>
|
94
|
+
<% if @crew %>
|
95
|
+
<%= link_to "Cancel", @crew, class: "btn btn-secondary" %>
|
96
|
+
<% else %>
|
97
|
+
<%= link_to "Cancel", tasks_path, class: "btn btn-secondary" %>
|
98
|
+
<% end %>
|
99
|
+
</div>
|
100
|
+
<% end %>
|
101
|
+
</div>
|
@@ -0,0 +1,129 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>Task #<%= @task.id %></h1>
|
3
|
+
<div class="actions">
|
4
|
+
<%= link_to "Edit Task", edit_task_path(@task), class: "btn btn-primary" %>
|
5
|
+
<% if @task.crew %>
|
6
|
+
<%= link_to "Back to Crew", @task.crew, class: "btn" %>
|
7
|
+
<% else %>
|
8
|
+
<%= link_to "All Tasks", tasks_path, class: "btn" %>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<div class="task-details">
|
14
|
+
<div class="details-grid">
|
15
|
+
<div class="detail-section">
|
16
|
+
<h3>Task Information</h3>
|
17
|
+
<div class="detail-item">
|
18
|
+
<strong>Description:</strong>
|
19
|
+
<p><%= @task.description %></p>
|
20
|
+
</div>
|
21
|
+
<div class="detail-item">
|
22
|
+
<strong>Expected Output:</strong>
|
23
|
+
<p><%= @task.expected_output %></p>
|
24
|
+
</div>
|
25
|
+
<% if @task.crew %>
|
26
|
+
<div class="detail-item">
|
27
|
+
<strong>Crew:</strong> <%= link_to @task.crew.name, @task.crew %>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
30
|
+
<% if @task.agent %>
|
31
|
+
<div class="detail-item">
|
32
|
+
<strong>Assigned Agent:</strong> <%= link_to @task.agent.name, @task.agent %>
|
33
|
+
</div>
|
34
|
+
<% end %>
|
35
|
+
<% if @task.output_file %>
|
36
|
+
<div class="detail-item">
|
37
|
+
<strong>Output File:</strong> <%= @task.output_file %>
|
38
|
+
</div>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<div class="detail-section">
|
43
|
+
<h3>Configuration</h3>
|
44
|
+
<div class="detail-item">
|
45
|
+
<strong>Status:</strong>
|
46
|
+
<span class="badge <%= @task.active ? 'badge-success' : 'badge-warning' %>">
|
47
|
+
<%= @task.active ? 'Active' : 'Inactive' %>
|
48
|
+
</span>
|
49
|
+
</div>
|
50
|
+
<div class="detail-item">
|
51
|
+
<strong>Async Execution:</strong>
|
52
|
+
<span class="badge <%= @task.async_execution ? 'badge-info' : 'badge-secondary' %>">
|
53
|
+
<%= @task.async_execution ? 'Enabled' : 'Disabled' %>
|
54
|
+
</span>
|
55
|
+
</div>
|
56
|
+
<div class="detail-item">
|
57
|
+
<strong>Order Index:</strong> <%= @task.order_index || 'Not set' %>
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<% if @task.context.present? %>
|
63
|
+
<div class="detail-section">
|
64
|
+
<h3>Context</h3>
|
65
|
+
<pre class="code-block"><%= @task.context %></pre>
|
66
|
+
</div>
|
67
|
+
<% end %>
|
68
|
+
|
69
|
+
<% if @task.config.present? %>
|
70
|
+
<div class="detail-section">
|
71
|
+
<h3>Configuration</h3>
|
72
|
+
<pre class="code-block"><%= JSON.pretty_generate(@task.config) %></pre>
|
73
|
+
</div>
|
74
|
+
<% end %>
|
75
|
+
|
76
|
+
<% if @task.tools_config.present? %>
|
77
|
+
<div class="detail-section">
|
78
|
+
<h3>Tools Configuration</h3>
|
79
|
+
<pre class="code-block"><%= JSON.pretty_generate(@task.tools_config) %></pre>
|
80
|
+
</div>
|
81
|
+
<% end %>
|
82
|
+
</div>
|
83
|
+
|
84
|
+
<div class="related-sections">
|
85
|
+
<div class="section">
|
86
|
+
<div class="section-header">
|
87
|
+
<h2>Dependencies (<%= @dependencies.count %>)</h2>
|
88
|
+
</div>
|
89
|
+
|
90
|
+
<% if @dependencies.any? %>
|
91
|
+
<div class="dependencies-list">
|
92
|
+
<% @dependencies.each do |dependency| %>
|
93
|
+
<div class="dependency-item">
|
94
|
+
<h4><%= link_to "Task ##{dependency.id}", dependency %></h4>
|
95
|
+
<p><%= truncate(dependency.description, length: 100) %></p>
|
96
|
+
<div class="dependency-actions">
|
97
|
+
<%= link_to "Remove", remove_dependency_task_path(@task, dependency_id: dependency.id),
|
98
|
+
method: :delete, class: "btn btn-sm btn-danger",
|
99
|
+
confirm: "Remove this dependency?" %>
|
100
|
+
</div>
|
101
|
+
</div>
|
102
|
+
<% end %>
|
103
|
+
</div>
|
104
|
+
<% else %>
|
105
|
+
<p>This task has no dependencies.</p>
|
106
|
+
<% end %>
|
107
|
+
|
108
|
+
<div class="add-dependency">
|
109
|
+
<h4>Add Dependency</h4>
|
110
|
+
<%= form_tag add_dependency_task_path(@task), method: :post do %>
|
111
|
+
<%= select_tag :dependency_id,
|
112
|
+
options_from_collection_for_select(
|
113
|
+
RcrewAI::Rails::Task.where.not(id: [@task.id] + @task.dependencies.pluck(:id)),
|
114
|
+
:id,
|
115
|
+
->(task) { "Task ##{task.id}: #{truncate(task.description, length: 50)}" }
|
116
|
+
),
|
117
|
+
{ prompt: 'Select a task to add as dependency' },
|
118
|
+
{ class: "form-select" } %>
|
119
|
+
<%= submit_tag "Add Dependency", class: "btn btn-sm btn-primary" %>
|
120
|
+
<% end %>
|
121
|
+
</div>
|
122
|
+
</div>
|
123
|
+
</div>
|
124
|
+
|
125
|
+
<div class="danger-zone">
|
126
|
+
<%= link_to "Delete Task", @task, method: :delete,
|
127
|
+
confirm: "Are you sure you want to delete this task? This action cannot be undone.",
|
128
|
+
class: "btn btn-danger" %>
|
129
|
+
</div>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>Edit Tool: <%= @tool.name %></h1>
|
3
|
+
<div class="actions">
|
4
|
+
<%= link_to "View Tool", [@agent, @tool], class: "btn" %>
|
5
|
+
<%= link_to "Back to Agent", @agent, class: "btn" %>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="form-container">
|
10
|
+
<%= form_with model: [@agent, @tool], local: true do |form| %>
|
11
|
+
<% if @tool.errors.any? %>
|
12
|
+
<div class="alert alert-error">
|
13
|
+
<h4><%= pluralize(@tool.errors.count, "error") %> prohibited this tool from being saved:</h4>
|
14
|
+
<ul>
|
15
|
+
<% @tool.errors.full_messages.each do |message| %>
|
16
|
+
<li><%= message %></li>
|
17
|
+
<% end %>
|
18
|
+
</ul>
|
19
|
+
</div>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<div class="form-group">
|
23
|
+
<%= form.label :name, class: "form-label" %>
|
24
|
+
<%= form.text_field :name, class: "form-input", required: true %>
|
25
|
+
<span class="form-help">Name of the tool</span>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<div class="form-group">
|
29
|
+
<%= form.label :description, class: "form-label" %>
|
30
|
+
<%= form.text_area :description, class: "form-input", rows: 3, required: true %>
|
31
|
+
<span class="form-help">Description of what this tool does</span>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="form-group">
|
35
|
+
<%= form.label :tool_class, "Tool Class", class: "form-label" %>
|
36
|
+
<%= form.text_field :tool_class, class: "form-input", required: true %>
|
37
|
+
<span class="form-help">The class name of the tool implementation</span>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class="form-group">
|
41
|
+
<%= form.label :config, "Configuration (JSON)", class: "form-label" %>
|
42
|
+
<%= form.text_area :config, class: "form-input", rows: 5 %>
|
43
|
+
<span class="form-help">Tool configuration in JSON format (optional)</span>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div class="form-group">
|
47
|
+
<%= form.label :active, class: "form-label" %>
|
48
|
+
<%= form.check_box :active, class: "form-checkbox" %>
|
49
|
+
<span class="form-help">Tool is active and available for use</span>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
<div class="form-actions">
|
53
|
+
<%= form.submit "Update Tool", class: "btn btn-primary" %>
|
54
|
+
<%= link_to "Cancel", [@agent, @tool], class: "btn btn-secondary" %>
|
55
|
+
<%= link_to "Delete Tool", [@agent, @tool], method: :delete,
|
56
|
+
confirm: "Are you sure you want to delete this tool?",
|
57
|
+
class: "btn btn-danger" %>
|
58
|
+
</div>
|
59
|
+
<% end %>
|
60
|
+
</div>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>Tools for <%= link_to @agent.name, @agent %></h1>
|
3
|
+
<div class="actions">
|
4
|
+
<%= link_to "New Tool", new_agent_tool_path(@agent), class: "btn btn-primary" %>
|
5
|
+
<%= link_to "Back to Agent", @agent, class: "btn" %>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="tools-grid">
|
10
|
+
<% if @tools.any? %>
|
11
|
+
<% @tools.each do |tool| %>
|
12
|
+
<div class="tool-card">
|
13
|
+
<div class="tool-header">
|
14
|
+
<h3><%= link_to tool.name, [@agent, tool] %></h3>
|
15
|
+
<span class="badge class-badge"><%= tool.tool_class %></span>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="tool-info">
|
19
|
+
<div class="info-item">
|
20
|
+
<strong>Description:</strong>
|
21
|
+
<p><%= truncate(tool.description, length: 150) %></p>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="tool-meta">
|
26
|
+
<% unless tool.active %>
|
27
|
+
<span class="badge badge-warning">Inactive</span>
|
28
|
+
<% else %>
|
29
|
+
<span class="badge badge-success">Active</span>
|
30
|
+
<% end %>
|
31
|
+
</div>
|
32
|
+
|
33
|
+
<div class="tool-actions">
|
34
|
+
<%= link_to "View", [@agent, tool], class: "btn btn-sm" %>
|
35
|
+
<%= link_to "Edit", edit_agent_tool_path(@agent, tool), class: "btn btn-sm" %>
|
36
|
+
<%= link_to "Delete", [@agent, tool], method: :delete,
|
37
|
+
confirm: "Are you sure?", class: "btn btn-sm btn-danger" %>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<% end %>
|
41
|
+
<% else %>
|
42
|
+
<div class="empty-state">
|
43
|
+
<h3>No tools found</h3>
|
44
|
+
<p>This agent doesn't have any tools configured yet.</p>
|
45
|
+
<%= link_to "Add First Tool", new_agent_tool_path(@agent), class: "btn btn-primary" %>
|
46
|
+
</div>
|
47
|
+
<% end %>
|
48
|
+
</div>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>New Tool for <%= link_to @agent.name, @agent %></h1>
|
3
|
+
<div class="actions">
|
4
|
+
<%= link_to "Back to Agent", @agent, class: "btn" %>
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="form-container">
|
9
|
+
<%= form_with model: [@agent, @tool], local: true do |form| %>
|
10
|
+
<% if @tool.errors.any? %>
|
11
|
+
<div class="alert alert-error">
|
12
|
+
<h4><%= pluralize(@tool.errors.count, "error") %> prohibited this tool from being saved:</h4>
|
13
|
+
<ul>
|
14
|
+
<% @tool.errors.full_messages.each do |message| %>
|
15
|
+
<li><%= message %></li>
|
16
|
+
<% end %>
|
17
|
+
</ul>
|
18
|
+
</div>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<div class="form-group">
|
22
|
+
<%= form.label :name, class: "form-label" %>
|
23
|
+
<%= form.text_field :name, class: "form-input", required: true %>
|
24
|
+
<span class="form-help">Name of the tool</span>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div class="form-group">
|
28
|
+
<%= form.label :description, class: "form-label" %>
|
29
|
+
<%= form.text_area :description, class: "form-input", rows: 3, required: true %>
|
30
|
+
<span class="form-help">Description of what this tool does</span>
|
31
|
+
</div>
|
32
|
+
|
33
|
+
<div class="form-group">
|
34
|
+
<%= form.label :tool_class, "Tool Class", class: "form-label" %>
|
35
|
+
<%= form.text_field :tool_class, class: "form-input", required: true %>
|
36
|
+
<span class="form-help">The class name of the tool implementation</span>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class="form-group">
|
40
|
+
<%= form.label :config, "Configuration (JSON)", class: "form-label" %>
|
41
|
+
<%= form.text_area :config, class: "form-input", rows: 5 %>
|
42
|
+
<span class="form-help">Tool configuration in JSON format (optional)</span>
|
43
|
+
</div>
|
44
|
+
|
45
|
+
<div class="form-group">
|
46
|
+
<%= form.label :active, class: "form-label" %>
|
47
|
+
<%= form.check_box :active, class: "form-checkbox", checked: true %>
|
48
|
+
<span class="form-help">Tool is active and available for use</span>
|
49
|
+
</div>
|
50
|
+
|
51
|
+
<div class="form-actions">
|
52
|
+
<%= form.submit "Create Tool", class: "btn btn-primary" %>
|
53
|
+
<%= link_to "Cancel", @agent, class: "btn btn-secondary" %>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
56
|
+
</div>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1><%= @tool.name %></h1>
|
3
|
+
<div class="actions">
|
4
|
+
<%= link_to "Edit Tool", edit_agent_tool_path(@agent, @tool), class: "btn btn-primary" %>
|
5
|
+
<%= link_to "Back to Agent", @agent, class: "btn" %>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="tool-details">
|
10
|
+
<div class="details-grid">
|
11
|
+
<div class="detail-section">
|
12
|
+
<h3>Tool Information</h3>
|
13
|
+
<div class="detail-item">
|
14
|
+
<strong>Name:</strong> <%= @tool.name %>
|
15
|
+
</div>
|
16
|
+
<div class="detail-item">
|
17
|
+
<strong>Description:</strong>
|
18
|
+
<p><%= @tool.description %></p>
|
19
|
+
</div>
|
20
|
+
<div class="detail-item">
|
21
|
+
<strong>Tool Class:</strong> <%= @tool.tool_class %>
|
22
|
+
</div>
|
23
|
+
<div class="detail-item">
|
24
|
+
<strong>Agent:</strong> <%= link_to @agent.name, @agent %>
|
25
|
+
</div>
|
26
|
+
<div class="detail-item">
|
27
|
+
<strong>Status:</strong>
|
28
|
+
<span class="badge <%= @tool.active ? 'badge-success' : 'badge-warning' %>">
|
29
|
+
<%= @tool.active ? 'Active' : 'Inactive' %>
|
30
|
+
</span>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<% if @tool.config.present? %>
|
36
|
+
<div class="detail-section">
|
37
|
+
<h3>Configuration</h3>
|
38
|
+
<pre class="code-block"><%= JSON.pretty_generate(@tool.config) %></pre>
|
39
|
+
</div>
|
40
|
+
<% end %>
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<div class="danger-zone">
|
44
|
+
<%= link_to "Delete Tool", [@agent, @tool], method: :delete,
|
45
|
+
confirm: "Are you sure you want to delete this tool? This action cannot be undone.",
|
46
|
+
class: "btn btn-danger" %>
|
47
|
+
</div>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class AddAgentToTasks < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
add_reference :rcrewai_tasks, :agent, null: true, foreign_key: { to_table: :rcrewai_agents }
|
4
|
+
add_column :rcrewai_tasks, :active, :boolean, default: true
|
5
|
+
add_column :rcrewai_tasks, :order_index, :integer, default: 0
|
6
|
+
|
7
|
+
add_index :rcrewai_tasks, :agent_id
|
8
|
+
add_index :rcrewai_tasks, :active
|
9
|
+
|
10
|
+
# Create tools table
|
11
|
+
create_table :rcrewai_tools do |t|
|
12
|
+
t.references :agent, null: false, foreign_key: { to_table: :rcrewai_agents }
|
13
|
+
t.string :name, null: false
|
14
|
+
t.text :description
|
15
|
+
t.string :tool_class, null: false
|
16
|
+
t.text :config
|
17
|
+
t.boolean :active, default: true
|
18
|
+
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
add_index :rcrewai_tools, :agent_id
|
23
|
+
add_index :rcrewai_tools, :active
|
24
|
+
end
|
25
|
+
end
|
data/lib/rcrewai/rails/engine.rb
CHANGED
@@ -2,6 +2,22 @@ module RcrewAI
|
|
2
2
|
module Rails
|
3
3
|
class Engine < ::Rails::Engine
|
4
4
|
isolate_namespace RcrewAI::Rails
|
5
|
+
|
6
|
+
# Fix inflector for RcrewAI constant
|
7
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
8
|
+
inflect.acronym 'AI'
|
9
|
+
inflect.acronym 'RcrewAI'
|
10
|
+
end
|
11
|
+
|
12
|
+
config.autoload_paths += %W[
|
13
|
+
#{config.root}/app
|
14
|
+
#{config.root}/lib
|
15
|
+
]
|
16
|
+
|
17
|
+
config.eager_load_paths += %W[
|
18
|
+
#{config.root}/app
|
19
|
+
#{config.root}/lib
|
20
|
+
]
|
5
21
|
|
6
22
|
config.generators do |g|
|
7
23
|
g.test_framework :rspec
|
@@ -14,17 +30,7 @@ module RcrewAI
|
|
14
30
|
app.config.assets.paths << root.join("app/assets/javascripts")
|
15
31
|
end
|
16
32
|
|
17
|
-
initializer "rcrewai_rails.load_models" do
|
18
|
-
ActiveSupport.on_load(:active_record) do
|
19
|
-
Dir[Engine.root.join("app/models/rcrewai/rails/*.rb")].each { |f| require f }
|
20
|
-
end
|
21
|
-
end
|
22
33
|
|
23
|
-
initializer "rcrewai_rails.load_jobs" do
|
24
|
-
ActiveSupport.on_load(:active_job) do
|
25
|
-
Dir[Engine.root.join("app/jobs/rcrewai/rails/*.rb")].each { |f| require f }
|
26
|
-
end
|
27
|
-
end
|
28
34
|
|
29
35
|
initializer "rcrewai_rails.configure" do |app|
|
30
36
|
RcrewAI::Rails.configure do |config|
|
data/rcrewai-rails.gemspec
CHANGED
@@ -6,8 +6,22 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.authors = ["gkosmo"]
|
7
7
|
spec.email = ["gkosmo1@hotmail.com"]
|
8
8
|
|
9
|
-
spec.summary = "Rails integration for RcrewAI - AI agent
|
10
|
-
spec.description =
|
9
|
+
spec.summary = "Rails integration for RcrewAI - Build AI agent crews with database persistence and web UI"
|
10
|
+
spec.description = <<~DESC
|
11
|
+
RcrewAI Rails is a comprehensive Rails engine that brings AI agent orchestration to your Rails applications.
|
12
|
+
Build intelligent AI crews that collaborate to solve complex tasks with full database persistence,
|
13
|
+
background job integration, and a beautiful web dashboard for monitoring and management.
|
14
|
+
|
15
|
+
Features:
|
16
|
+
• ActiveRecord models for crews, agents, tasks, and executions with full persistence
|
17
|
+
• Rails generators for scaffolding AI crews and agents
|
18
|
+
• ActiveJob integration for asynchronous crew execution (works with any Rails background job adapter)
|
19
|
+
• Web dashboard with real-time monitoring and management interface
|
20
|
+
• Multi-LLM support: OpenAI GPT, Anthropic Claude, Google Gemini, Azure OpenAI, Ollama
|
21
|
+
• Production-ready with logging, error handling, and security controls
|
22
|
+
• Human-in-the-loop workflows with approval mechanisms
|
23
|
+
• Tool ecosystem: web search, file operations, SQL, email, code execution
|
24
|
+
DESC
|
11
25
|
spec.homepage = "https://github.com/gkosmo/rcrewai-rails"
|
12
26
|
spec.license = "MIT"
|
13
27
|
spec.required_ruby_version = ">= 3.0.0"
|
@@ -15,6 +29,10 @@ Gem::Specification.new do |spec|
|
|
15
29
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
30
|
spec.metadata["source_code_uri"] = spec.homepage
|
17
31
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
32
|
+
spec.metadata["documentation_uri"] = "https://gkosmo.github.io/rcrewAI/"
|
33
|
+
spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
|
34
|
+
spec.metadata["wiki_uri"] = "#{spec.homepage}/wiki"
|
35
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
18
36
|
|
19
37
|
spec.files = Dir.chdir(__dir__) do
|
20
38
|
`git ls-files -z`.split("\x0").reject do |f|
|