deepagents_rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +309 -0
- data/lib/deepagents_rails/service.rb +93 -0
- data/lib/deepagents_rails/version.rb +3 -0
- data/lib/deepagents_rails.rb +31 -0
- data/lib/generators/deepagents/agent/agent_generator.rb +55 -0
- data/lib/generators/deepagents/agent/templates/agent.rb +99 -0
- data/lib/generators/deepagents/agent/templates/agent_spec.rb +33 -0
- data/lib/generators/deepagents/agent/templates/controller.rb +44 -0
- data/lib/generators/deepagents/agent/templates/index.html.erb +178 -0
- data/lib/generators/deepagents/agent/templates/show.html.erb +131 -0
- data/lib/generators/deepagents/controller/controller_generator.rb +51 -0
- data/lib/generators/deepagents/controller/templates/api_controller.rb +87 -0
- data/lib/generators/deepagents/controller/templates/serializer.rb +22 -0
- data/lib/generators/deepagents/install/install_generator.rb +41 -0
- data/lib/generators/deepagents/install/templates/deepagents.yml +38 -0
- data/lib/generators/deepagents/install/templates/initializer.rb +35 -0
- data/lib/generators/deepagents/model/model_generator.rb +43 -0
- data/lib/generators/deepagents/model/templates/conversation.rb +73 -0
- data/lib/generators/deepagents/model/templates/create_conversations_migration.rb +16 -0
- data/lib/generators/deepagents/model/templates/create_files_migration.rb +17 -0
- data/lib/generators/deepagents/model/templates/create_messages_migration.rb +17 -0
- data/lib/generators/deepagents/model/templates/file.rb +96 -0
- data/lib/generators/deepagents/model/templates/message.rb +30 -0
- data/lib/generators/deepagents/tool/templates/tool.rb +27 -0
- data/lib/generators/deepagents/tool/templates/tool_spec.rb +36 -0
- data/lib/generators/deepagents/tool/tool_generator.rb +58 -0
- data/lib/generators/deepagents/view/templates/_conversation.html.erb +10 -0
- data/lib/generators/deepagents/view/templates/_form.html.erb +33 -0
- data/lib/generators/deepagents/view/templates/_message.html.erb +31 -0
- data/lib/generators/deepagents/view/templates/index.html.erb +35 -0
- data/lib/generators/deepagents/view/templates/javascript.js +199 -0
- data/lib/generators/deepagents/view/templates/new.html.erb +10 -0
- data/lib/generators/deepagents/view/templates/show.html.erb +54 -0
- data/lib/generators/deepagents/view/templates/stylesheet.css +397 -0
- data/lib/generators/deepagents/view/view_generator.rb +50 -0
- metadata +121 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deepagents
|
|
4
|
+
class <%= class_name %>Conversation < ApplicationRecord
|
|
5
|
+
self.table_name = 'deepagents_<%= file_name %>_conversations'
|
|
6
|
+
|
|
7
|
+
has_many :<%= file_name %>_messages, class_name: 'Deepagents::<%= class_name %>Message', foreign_key: 'conversation_id', dependent: :destroy
|
|
8
|
+
has_many :<%= file_name %>_files, class_name: 'Deepagents::<%= class_name %>File', foreign_key: 'conversation_id', dependent: :destroy
|
|
9
|
+
|
|
10
|
+
# Alias for easier access
|
|
11
|
+
alias_method :messages, :<%= file_name %>_messages
|
|
12
|
+
alias_method :files, :<%= file_name %>_files
|
|
13
|
+
|
|
14
|
+
# Scopes
|
|
15
|
+
scope :recent, -> { order(created_at: :desc) }
|
|
16
|
+
|
|
17
|
+
# Convert to format expected by DeepAgents
|
|
18
|
+
def to_agent_format
|
|
19
|
+
{
|
|
20
|
+
messages: messages.order(:created_at).map(&:to_agent_format),
|
|
21
|
+
files: files_hash
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Run the agent with the current conversation context
|
|
26
|
+
def run_agent(input, agent_name = nil)
|
|
27
|
+
# Create a new message for the user input
|
|
28
|
+
user_message = messages.create!(
|
|
29
|
+
role: 'user',
|
|
30
|
+
content: input
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Get the service
|
|
34
|
+
service = DeepagentsRails.service(agent_name)
|
|
35
|
+
|
|
36
|
+
# Run the agent with the conversation context
|
|
37
|
+
result = service.run(input, to_agent_format)
|
|
38
|
+
|
|
39
|
+
# Create a new message for the agent response
|
|
40
|
+
assistant_message = messages.create!(
|
|
41
|
+
role: 'assistant',
|
|
42
|
+
content: result[:response]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Save any files generated by the agent
|
|
46
|
+
if result[:files].present?
|
|
47
|
+
result[:files].each do |filename, content|
|
|
48
|
+
files.create!(
|
|
49
|
+
filename: filename,
|
|
50
|
+
content: content
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Return the result
|
|
56
|
+
{
|
|
57
|
+
message: assistant_message,
|
|
58
|
+
files: result[:files]
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# Convert files to hash format expected by DeepAgents
|
|
65
|
+
def files_hash
|
|
66
|
+
hash = {}
|
|
67
|
+
files.each do |file|
|
|
68
|
+
hash[file.filename] = file.content
|
|
69
|
+
end
|
|
70
|
+
hash
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateDeepagents<%= class_name.pluralize %>Conversations < ActiveRecord::Migration[6.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :deepagents_<%= file_name %>_conversations do |t|
|
|
6
|
+
t.string :title
|
|
7
|
+
t.references :user, polymorphic: true, index: { name: 'index_<%= file_name %>_conversations_on_user' }
|
|
8
|
+
t.string :agent_name
|
|
9
|
+
t.jsonb :metadata, default: {}
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :deepagents_<%= file_name %>_conversations, :created_at
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateDeepagents<%= class_name.pluralize %>Files < ActiveRecord::Migration[6.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :deepagents_<%= file_name %>_files do |t|
|
|
6
|
+
t.references :conversation, null: false, foreign_key: { to_table: :deepagents_<%= file_name %>_conversations }, index: { name: 'index_<%= file_name %>_files_on_conversation_id' }
|
|
7
|
+
t.string :filename, null: false
|
|
8
|
+
t.text :content, null: false
|
|
9
|
+
t.jsonb :metadata, default: {}
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :deepagents_<%= file_name %>_files, :created_at
|
|
15
|
+
add_index :deepagents_<%= file_name %>_files, :filename
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateDeepagents<%= class_name.pluralize %>Messages < ActiveRecord::Migration[6.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :deepagents_<%= file_name %>_messages do |t|
|
|
6
|
+
t.references :conversation, null: false, foreign_key: { to_table: :deepagents_<%= file_name %>_conversations }, index: { name: 'index_<%= file_name %>_messages_on_conversation_id' }
|
|
7
|
+
t.string :role, null: false
|
|
8
|
+
t.text :content, null: false
|
|
9
|
+
t.jsonb :metadata, default: {}
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :deepagents_<%= file_name %>_messages, :created_at
|
|
15
|
+
add_index :deepagents_<%= file_name %>_messages, :role
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deepagents
|
|
4
|
+
class <%= class_name %>File < ApplicationRecord
|
|
5
|
+
self.table_name = 'deepagents_<%= file_name %>_files'
|
|
6
|
+
|
|
7
|
+
belongs_to :<%= file_name %>_conversation, class_name: 'Deepagents::<%= class_name %>Conversation', foreign_key: 'conversation_id'
|
|
8
|
+
|
|
9
|
+
# Alias for easier access
|
|
10
|
+
alias_method :conversation, :<%= file_name %>_conversation
|
|
11
|
+
|
|
12
|
+
# Validations
|
|
13
|
+
validates :filename, presence: true
|
|
14
|
+
validates :content, presence: true
|
|
15
|
+
|
|
16
|
+
# Get the file extension
|
|
17
|
+
def extension
|
|
18
|
+
File.extname(filename).delete('.')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Check if the file is an image
|
|
22
|
+
def image?
|
|
23
|
+
%w[jpg jpeg png gif svg webp].include?(extension.downcase)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Check if the file is a text file
|
|
27
|
+
def text?
|
|
28
|
+
%w[txt md markdown rb py js html css json yaml yml xml].include?(extension.downcase)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Generate a URL for the file (if using Active Storage)
|
|
32
|
+
def url
|
|
33
|
+
if defined?(ActiveStorage) && attachment.present?
|
|
34
|
+
Rails.application.routes.url_helpers.rails_blob_path(attachment, only_path: true)
|
|
35
|
+
else
|
|
36
|
+
"#"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Attach the file content to Active Storage (if available)
|
|
41
|
+
def attach_content
|
|
42
|
+
return unless defined?(ActiveStorage)
|
|
43
|
+
|
|
44
|
+
# Create a tempfile with the content
|
|
45
|
+
tempfile = Tempfile.new([filename, ".#{extension}"])
|
|
46
|
+
tempfile.binmode
|
|
47
|
+
tempfile.write(content)
|
|
48
|
+
tempfile.rewind
|
|
49
|
+
|
|
50
|
+
# Attach the tempfile
|
|
51
|
+
attachment.attach(
|
|
52
|
+
io: tempfile,
|
|
53
|
+
filename: filename,
|
|
54
|
+
content_type: content_type
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Close and delete the tempfile
|
|
58
|
+
tempfile.close
|
|
59
|
+
tempfile.unlink
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# Determine the content type based on the extension
|
|
65
|
+
def content_type
|
|
66
|
+
case extension.downcase
|
|
67
|
+
when 'jpg', 'jpeg'
|
|
68
|
+
'image/jpeg'
|
|
69
|
+
when 'png'
|
|
70
|
+
'image/png'
|
|
71
|
+
when 'gif'
|
|
72
|
+
'image/gif'
|
|
73
|
+
when 'svg'
|
|
74
|
+
'image/svg+xml'
|
|
75
|
+
when 'txt'
|
|
76
|
+
'text/plain'
|
|
77
|
+
when 'md', 'markdown'
|
|
78
|
+
'text/markdown'
|
|
79
|
+
when 'html'
|
|
80
|
+
'text/html'
|
|
81
|
+
when 'css'
|
|
82
|
+
'text/css'
|
|
83
|
+
when 'js'
|
|
84
|
+
'application/javascript'
|
|
85
|
+
when 'json'
|
|
86
|
+
'application/json'
|
|
87
|
+
when 'yaml', 'yml'
|
|
88
|
+
'application/yaml'
|
|
89
|
+
when 'xml'
|
|
90
|
+
'application/xml'
|
|
91
|
+
else
|
|
92
|
+
'application/octet-stream'
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deepagents
|
|
4
|
+
class <%= class_name %>Message < ApplicationRecord
|
|
5
|
+
self.table_name = 'deepagents_<%= file_name %>_messages'
|
|
6
|
+
|
|
7
|
+
belongs_to :<%= file_name %>_conversation, class_name: 'Deepagents::<%= class_name %>Conversation', foreign_key: 'conversation_id'
|
|
8
|
+
|
|
9
|
+
# Alias for easier access
|
|
10
|
+
alias_method :conversation, :<%= file_name %>_conversation
|
|
11
|
+
|
|
12
|
+
# Validations
|
|
13
|
+
validates :role, presence: true, inclusion: { in: %w[user assistant system] }
|
|
14
|
+
validates :content, presence: true
|
|
15
|
+
|
|
16
|
+
# Scopes
|
|
17
|
+
scope :user, -> { where(role: 'user') }
|
|
18
|
+
scope :assistant, -> { where(role: 'assistant') }
|
|
19
|
+
scope :system, -> { where(role: 'system') }
|
|
20
|
+
scope :chronological, -> { order(created_at: :asc) }
|
|
21
|
+
|
|
22
|
+
# Convert to format expected by DeepAgents
|
|
23
|
+
def to_agent_format
|
|
24
|
+
{
|
|
25
|
+
role: role,
|
|
26
|
+
content: content
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deepagents
|
|
4
|
+
module Tools
|
|
5
|
+
class <%= class_name %>Tool
|
|
6
|
+
# Returns a DeepAgents::Tool instance
|
|
7
|
+
def self.build
|
|
8
|
+
DeepAgents::Tool.new(
|
|
9
|
+
"<%= file_name %>",
|
|
10
|
+
"<%= tool_description %>"
|
|
11
|
+
) do |<%= parameters_with_defaults %>|
|
|
12
|
+
# Implement your tool's functionality here
|
|
13
|
+
# This block will be called when the agent uses this tool
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
# Example implementation - replace with your actual logic
|
|
17
|
+
"Result of <%= file_name %> operation with parameters: #{[<%= parameters_as_args %>].join(', ')}"
|
|
18
|
+
rescue => e
|
|
19
|
+
"Error in <%= file_name %> tool: #{e.message}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Optional: Add helper methods for your tool below
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Deepagents::Tools::<%= class_name %>Tool do
|
|
6
|
+
describe '.build' do
|
|
7
|
+
it 'returns a DeepAgents::Tool instance' do
|
|
8
|
+
tool = described_class.build
|
|
9
|
+
expect(tool).to be_a(DeepAgents::Tool)
|
|
10
|
+
expect(tool.name).to eq('<%= file_name %>')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'has the correct description' do
|
|
14
|
+
tool = described_class.build
|
|
15
|
+
expect(tool.description).to eq('<%= tool_description %>')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'executes the tool functionality' do
|
|
19
|
+
tool = described_class.build
|
|
20
|
+
# Test with sample parameters - adjust based on your tool's parameters
|
|
21
|
+
result = tool.execute(<% tool_parameters.each_with_index do |param, i| %><%= i > 0 ? ', ' : '' %>'test_<%= param %>'<% end %>)
|
|
22
|
+
expect(result).to be_a(String)
|
|
23
|
+
expect(result).to include('Result of <%= file_name %> operation')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'handles errors gracefully' do
|
|
27
|
+
tool = described_class.build
|
|
28
|
+
|
|
29
|
+
# Mock an error in the tool execution
|
|
30
|
+
allow_any_instance_of(DeepAgents::Tool).to receive(:execute).and_raise(StandardError.new('Test error'))
|
|
31
|
+
|
|
32
|
+
# The tool should catch the error and return an error message
|
|
33
|
+
expect { tool.execute(<% tool_parameters.each_with_index do |param, i| %><%= i > 0 ? ', ' : '' %>'test_<%= param %>'<% end %>) }.not_to raise_error
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Deepagents
|
|
2
|
+
module Generators
|
|
3
|
+
class ToolGenerator < Rails::Generators::NamedBase
|
|
4
|
+
source_root File.expand_path('templates', __dir__)
|
|
5
|
+
|
|
6
|
+
desc "Creates a new DeepAgents tool for your Rails application"
|
|
7
|
+
|
|
8
|
+
class_option :description, type: :string, default: "", desc: "Description of what the tool does"
|
|
9
|
+
class_option :parameters, type: :array, default: [], desc: "Parameters for the tool"
|
|
10
|
+
|
|
11
|
+
def create_tool_file
|
|
12
|
+
template "tool.rb", "app/deepagents/tools/#{file_name}_tool.rb"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_tool_spec_file
|
|
16
|
+
template "tool_spec.rb", "spec/deepagents/tools/#{file_name}_tool_spec.rb"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def display_next_steps
|
|
20
|
+
say "\n"
|
|
21
|
+
say "Tool #{file_name} has been created! 🔧", :green
|
|
22
|
+
say "\n"
|
|
23
|
+
say "Next steps:", :yellow
|
|
24
|
+
say " 1. Edit app/deepagents/tools/#{file_name}_tool.rb to implement your tool's functionality"
|
|
25
|
+
say " 2. Add this tool to your agents by including it in the tools array"
|
|
26
|
+
say "\n"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def tool_description
|
|
32
|
+
options[:description].present? ? options[:description] : "Performs #{file_name} operations"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def tool_parameters
|
|
36
|
+
options[:parameters].empty? ? ["query"] : options[:parameters]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def parameters_as_args
|
|
40
|
+
params = tool_parameters
|
|
41
|
+
if params.size == 1
|
|
42
|
+
params.first
|
|
43
|
+
else
|
|
44
|
+
params.join(", ")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def parameters_with_defaults
|
|
49
|
+
params = tool_parameters
|
|
50
|
+
if params.size == 1
|
|
51
|
+
"#{params.first}"
|
|
52
|
+
else
|
|
53
|
+
params.map { |p| "#{p}" }.join(", ")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%# DeepAgents %> <%= class_name %> <%# Conversation Partial %>
|
|
2
|
+
<% if conversation.messages.any? %>
|
|
3
|
+
<% conversation.messages.order(:created_at).each do |message| %>
|
|
4
|
+
<%= render partial: "message", locals: { message: message } %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<% else %>
|
|
7
|
+
<div class="deepagents-empty-state">
|
|
8
|
+
<p>No messages yet. Start the conversation by typing a message below.</p>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<%# DeepAgents %> <%= class_name %> <%# Form Partial %>
|
|
2
|
+
<%= form_with(model: #{file_name}, local: true, class: "deepagents-form") do |form| %>
|
|
3
|
+
<% if #{file_name}.errors.any? %>
|
|
4
|
+
<div class="deepagents-error-messages">
|
|
5
|
+
<h2><%= pluralize(#{file_name}.errors.count, "error") %> prohibited this conversation from being saved:</h2>
|
|
6
|
+
<ul>
|
|
7
|
+
<% #{file_name}.errors.full_messages.each do |message| %>
|
|
8
|
+
<li><%= message %></li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<div class="deepagents-form-group">
|
|
15
|
+
<%= form.label :title %>
|
|
16
|
+
<%= form.text_field :title, class: "deepagents-form-control" %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="deepagents-form-group">
|
|
20
|
+
<%= form.label :agent_name %>
|
|
21
|
+
<%= form.select :agent_name, DeepagentsRails.service.available_agents.map { |name| [name.titleize, name] }, { include_blank: "Default Agent" }, class: "deepagents-form-control" %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="deepagents-form-group">
|
|
25
|
+
<%= form.label :system_message, "System Instructions" %>
|
|
26
|
+
<%= form.text_area :system_message, class: "deepagents-form-control", rows: 3 %>
|
|
27
|
+
<small class="deepagents-form-text">Optional instructions to guide the agent's behavior</small>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="deepagents-form-actions">
|
|
31
|
+
<%= form.submit "Create Conversation", class: "deepagents-button" %>
|
|
32
|
+
</div>
|
|
33
|
+
<% end %>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<%# DeepAgents %> <%= class_name %> <%# Message Partial %>
|
|
2
|
+
<div class="deepagents-message <%= message.role %>">
|
|
3
|
+
<div class="deepagents-message-avatar">
|
|
4
|
+
<% if message.role == 'user' %>
|
|
5
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16">
|
|
6
|
+
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/>
|
|
7
|
+
</svg>
|
|
8
|
+
<% elsif message.role == 'assistant' %>
|
|
9
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16">
|
|
10
|
+
<path d="M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5ZM3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.58 26.58 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.933.933 0 0 1-.765.935c-.845.147-2.34.346-4.235.346-1.895 0-3.39-.2-4.235-.346A.933.933 0 0 1 3 9.219V8.062Zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a24.767 24.767 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25.286 25.286 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135Z"/>
|
|
11
|
+
<path d="M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2V1.866ZM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5Z"/>
|
|
12
|
+
</svg>
|
|
13
|
+
<% else %>
|
|
14
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16">
|
|
15
|
+
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
|
16
|
+
<path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/>
|
|
17
|
+
</svg>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="deepagents-message-content">
|
|
22
|
+
<div class="deepagents-message-header">
|
|
23
|
+
<span class="deepagents-message-role"><%= message.role.capitalize %></span>
|
|
24
|
+
<span class="deepagents-message-timestamp"><%= time_ago_in_words(message.created_at) %> ago</span>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="deepagents-message-body">
|
|
28
|
+
<%= simple_format(message.content) %>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<%# DeepAgents %> <%= class_name %> <%# Index View %>
|
|
2
|
+
<div class="deepagents-container">
|
|
3
|
+
<h1>Conversations</h1>
|
|
4
|
+
|
|
5
|
+
<div class="deepagents-actions">
|
|
6
|
+
<%= link_to "New Conversation", new_#{file_name}_path, class: "deepagents-button" %>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="deepagents-conversations-list">
|
|
10
|
+
<% if @conversations.any? %>
|
|
11
|
+
<% @conversations.each do |conversation| %>
|
|
12
|
+
<div class="deepagents-conversation-card">
|
|
13
|
+
<h3><%= link_to conversation.title.presence || "Conversation ##{conversation.id}", #{file_name}_path(conversation) %></h3>
|
|
14
|
+
<div class="deepagents-conversation-meta">
|
|
15
|
+
<span class="deepagents-timestamp"><%= time_ago_in_words(conversation.created_at) %> ago</span>
|
|
16
|
+
<% if conversation.agent_name.present? %>
|
|
17
|
+
<span class="deepagents-agent-name"><%= conversation.agent_name %></span>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="deepagents-conversation-preview">
|
|
21
|
+
<% if conversation.messages.any? %>
|
|
22
|
+
<%= truncate(conversation.messages.last.content, length: 100) %>
|
|
23
|
+
<% else %>
|
|
24
|
+
<em>No messages yet</em>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% else %>
|
|
30
|
+
<div class="deepagents-empty-state">
|
|
31
|
+
<p>No conversations yet. <%= link_to "Start a new conversation", new_#{file_name}_path %>.</p>
|
|
32
|
+
</div>
|
|
33
|
+
<% end %>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|