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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +309 -0
  4. data/lib/deepagents_rails/service.rb +93 -0
  5. data/lib/deepagents_rails/version.rb +3 -0
  6. data/lib/deepagents_rails.rb +31 -0
  7. data/lib/generators/deepagents/agent/agent_generator.rb +55 -0
  8. data/lib/generators/deepagents/agent/templates/agent.rb +99 -0
  9. data/lib/generators/deepagents/agent/templates/agent_spec.rb +33 -0
  10. data/lib/generators/deepagents/agent/templates/controller.rb +44 -0
  11. data/lib/generators/deepagents/agent/templates/index.html.erb +178 -0
  12. data/lib/generators/deepagents/agent/templates/show.html.erb +131 -0
  13. data/lib/generators/deepagents/controller/controller_generator.rb +51 -0
  14. data/lib/generators/deepagents/controller/templates/api_controller.rb +87 -0
  15. data/lib/generators/deepagents/controller/templates/serializer.rb +22 -0
  16. data/lib/generators/deepagents/install/install_generator.rb +41 -0
  17. data/lib/generators/deepagents/install/templates/deepagents.yml +38 -0
  18. data/lib/generators/deepagents/install/templates/initializer.rb +35 -0
  19. data/lib/generators/deepagents/model/model_generator.rb +43 -0
  20. data/lib/generators/deepagents/model/templates/conversation.rb +73 -0
  21. data/lib/generators/deepagents/model/templates/create_conversations_migration.rb +16 -0
  22. data/lib/generators/deepagents/model/templates/create_files_migration.rb +17 -0
  23. data/lib/generators/deepagents/model/templates/create_messages_migration.rb +17 -0
  24. data/lib/generators/deepagents/model/templates/file.rb +96 -0
  25. data/lib/generators/deepagents/model/templates/message.rb +30 -0
  26. data/lib/generators/deepagents/tool/templates/tool.rb +27 -0
  27. data/lib/generators/deepagents/tool/templates/tool_spec.rb +36 -0
  28. data/lib/generators/deepagents/tool/tool_generator.rb +58 -0
  29. data/lib/generators/deepagents/view/templates/_conversation.html.erb +10 -0
  30. data/lib/generators/deepagents/view/templates/_form.html.erb +33 -0
  31. data/lib/generators/deepagents/view/templates/_message.html.erb +31 -0
  32. data/lib/generators/deepagents/view/templates/index.html.erb +35 -0
  33. data/lib/generators/deepagents/view/templates/javascript.js +199 -0
  34. data/lib/generators/deepagents/view/templates/new.html.erb +10 -0
  35. data/lib/generators/deepagents/view/templates/show.html.erb +54 -0
  36. data/lib/generators/deepagents/view/templates/stylesheet.css +397 -0
  37. data/lib/generators/deepagents/view/view_generator.rb +50 -0
  38. metadata +121 -0
@@ -0,0 +1,178 @@
1
+ <%# DeepAgents <%= class_name %> Agent Interface %>
2
+
3
+ <div class="deepagents-container">
4
+ <div class="deepagents-header">
5
+ <h1><%= class_name %> Agent</h1>
6
+ <p>Ask a question or provide instructions to interact with the agent.</p>
7
+ </div>
8
+
9
+ <div class="deepagents-conversation" id="conversation">
10
+ <% if @messages.present? %>
11
+ <% @messages.each do |message| %>
12
+ <div class="message <%= message[:role] %>">
13
+ <div class="message-content">
14
+ <%= simple_format(message[:content]) %>
15
+ </div>
16
+ <div class="message-timestamp">
17
+ <%= message[:timestamp].strftime("%H:%M") %>
18
+ </div>
19
+ </div>
20
+ <% end %>
21
+ <% else %>
22
+ <div class="empty-state">
23
+ <p>No messages yet. Start a conversation with the agent.</p>
24
+ </div>
25
+ <% end %>
26
+ </div>
27
+
28
+ <%= form_with url: deepagents_<%= file_name %>_index_path, method: :post, class: "deepagents-input-form", id: "agent-form", data: { remote: true } do |f| %>
29
+ <div class="input-container">
30
+ <%= f.text_area :input, placeholder: "Type your message here...", rows: 3, class: "deepagents-input", id: "agent-input" %>
31
+
32
+ <div class="file-upload-container">
33
+ <%= f.file_field :files, multiple: true, class: "file-input", id: "file-upload" %>
34
+ <label for="file-upload" class="file-upload-button">
35
+ <i class="fa fa-paperclip"></i> Attach Files
36
+ </label>
37
+ </div>
38
+
39
+ <%= f.submit "Send", class: "send-button", id: "send-button" %>
40
+ </div>
41
+ <% end %>
42
+ </div>
43
+
44
+ <style>
45
+ .deepagents-container {
46
+ max-width: 800px;
47
+ margin: 0 auto;
48
+ padding: 20px;
49
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
50
+ }
51
+
52
+ .deepagents-header {
53
+ margin-bottom: 20px;
54
+ text-align: center;
55
+ }
56
+
57
+ .deepagents-conversation {
58
+ border: 1px solid #e0e0e0;
59
+ border-radius: 8px;
60
+ padding: 15px;
61
+ height: 400px;
62
+ overflow-y: auto;
63
+ margin-bottom: 20px;
64
+ background-color: #f9f9f9;
65
+ }
66
+
67
+ .message {
68
+ margin-bottom: 15px;
69
+ padding: 10px 15px;
70
+ border-radius: 8px;
71
+ max-width: 80%;
72
+ }
73
+
74
+ .message.user {
75
+ background-color: #e1f5fe;
76
+ margin-left: auto;
77
+ }
78
+
79
+ .message.assistant {
80
+ background-color: #f0f0f0;
81
+ margin-right: auto;
82
+ }
83
+
84
+ .message-timestamp {
85
+ font-size: 0.8em;
86
+ color: #888;
87
+ text-align: right;
88
+ margin-top: 5px;
89
+ }
90
+
91
+ .input-container {
92
+ display: flex;
93
+ flex-direction: column;
94
+ gap: 10px;
95
+ }
96
+
97
+ .deepagents-input {
98
+ width: 100%;
99
+ padding: 10px;
100
+ border: 1px solid #ddd;
101
+ border-radius: 8px;
102
+ resize: none;
103
+ }
104
+
105
+ .file-upload-container {
106
+ display: flex;
107
+ align-items: center;
108
+ }
109
+
110
+ .file-input {
111
+ display: none;
112
+ }
113
+
114
+ .file-upload-button {
115
+ display: inline-block;
116
+ padding: 8px 12px;
117
+ background-color: #f0f0f0;
118
+ border-radius: 4px;
119
+ cursor: pointer;
120
+ font-size: 0.9em;
121
+ }
122
+
123
+ .send-button {
124
+ padding: 10px 20px;
125
+ background-color: #2196f3;
126
+ color: white;
127
+ border: none;
128
+ border-radius: 8px;
129
+ cursor: pointer;
130
+ font-weight: bold;
131
+ }
132
+
133
+ .send-button:hover {
134
+ background-color: #1976d2;
135
+ }
136
+
137
+ .empty-state {
138
+ text-align: center;
139
+ color: #888;
140
+ padding: 40px 0;
141
+ }
142
+ </style>
143
+
144
+ <script>
145
+ document.addEventListener('DOMContentLoaded', function() {
146
+ const form = document.getElementById('agent-form');
147
+ const input = document.getElementById('agent-input');
148
+ const conversation = document.getElementById('conversation');
149
+
150
+ form.addEventListener('ajax:success', function(event) {
151
+ const [data, status, xhr] = event.detail;
152
+
153
+ // Add user message
154
+ const userMessage = document.createElement('div');
155
+ userMessage.className = 'message user';
156
+ userMessage.innerHTML = `
157
+ <div class="message-content">${input.value.replace(/\n/g, '<br>')}</div>
158
+ <div class="message-timestamp">${new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</div>
159
+ `;
160
+ conversation.appendChild(userMessage);
161
+
162
+ // Add assistant message
163
+ const assistantMessage = document.createElement('div');
164
+ assistantMessage.className = 'message assistant';
165
+ assistantMessage.innerHTML = `
166
+ <div class="message-content">${data.response.replace(/\n/g, '<br>')}</div>
167
+ <div class="message-timestamp">${new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</div>
168
+ `;
169
+ conversation.appendChild(assistantMessage);
170
+
171
+ // Clear input
172
+ input.value = '';
173
+
174
+ // Scroll to bottom
175
+ conversation.scrollTop = conversation.scrollHeight;
176
+ });
177
+ });
178
+ </script>
@@ -0,0 +1,131 @@
1
+ <%# DeepAgents <%= class_name %> Agent Conversation View %>
2
+
3
+ <div class="deepagents-container">
4
+ <div class="deepagents-header">
5
+ <h1>Conversation #<%= @conversation.id %></h1>
6
+ <p><%= @conversation.created_at.strftime("%B %d, %Y at %H:%M") %></p>
7
+ <%= link_to "Back to All Conversations", deepagents_<%= file_name %>_index_path, class: "back-link" %>
8
+ </div>
9
+
10
+ <div class="deepagents-conversation" id="conversation">
11
+ <% @conversation.messages.each do |message| %>
12
+ <div class="message <%= message.role %>">
13
+ <div class="message-content">
14
+ <%= simple_format(message.content) %>
15
+ </div>
16
+ <div class="message-timestamp">
17
+ <%= message.created_at.strftime("%H:%M") %>
18
+ </div>
19
+ </div>
20
+ <% end %>
21
+ </div>
22
+
23
+ <% if @conversation.files.any? %>
24
+ <div class="files-section">
25
+ <h3>Files</h3>
26
+ <div class="files-container">
27
+ <% @conversation.files.each do |file| %>
28
+ <div class="file-item">
29
+ <div class="file-name"><%= file.filename %></div>
30
+ <div class="file-actions">
31
+ <%= link_to "Download", file.url, class: "file-download" %>
32
+ </div>
33
+ </div>
34
+ <% end %>
35
+ </div>
36
+ </div>
37
+ <% end %>
38
+ </div>
39
+
40
+ <style>
41
+ .deepagents-container {
42
+ max-width: 800px;
43
+ margin: 0 auto;
44
+ padding: 20px;
45
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
46
+ }
47
+
48
+ .deepagents-header {
49
+ margin-bottom: 20px;
50
+ }
51
+
52
+ .back-link {
53
+ display: inline-block;
54
+ margin-top: 10px;
55
+ color: #2196f3;
56
+ text-decoration: none;
57
+ }
58
+
59
+ .back-link:hover {
60
+ text-decoration: underline;
61
+ }
62
+
63
+ .deepagents-conversation {
64
+ border: 1px solid #e0e0e0;
65
+ border-radius: 8px;
66
+ padding: 15px;
67
+ max-height: 600px;
68
+ overflow-y: auto;
69
+ margin-bottom: 20px;
70
+ background-color: #f9f9f9;
71
+ }
72
+
73
+ .message {
74
+ margin-bottom: 15px;
75
+ padding: 10px 15px;
76
+ border-radius: 8px;
77
+ max-width: 80%;
78
+ }
79
+
80
+ .message.user {
81
+ background-color: #e1f5fe;
82
+ margin-left: auto;
83
+ }
84
+
85
+ .message.assistant {
86
+ background-color: #f0f0f0;
87
+ margin-right: auto;
88
+ }
89
+
90
+ .message-timestamp {
91
+ font-size: 0.8em;
92
+ color: #888;
93
+ text-align: right;
94
+ margin-top: 5px;
95
+ }
96
+
97
+ .files-section {
98
+ margin-top: 30px;
99
+ }
100
+
101
+ .files-container {
102
+ display: flex;
103
+ flex-wrap: wrap;
104
+ gap: 10px;
105
+ }
106
+
107
+ .file-item {
108
+ border: 1px solid #e0e0e0;
109
+ border-radius: 4px;
110
+ padding: 10px;
111
+ width: calc(50% - 5px);
112
+ display: flex;
113
+ justify-content: space-between;
114
+ align-items: center;
115
+ }
116
+
117
+ .file-name {
118
+ font-size: 0.9em;
119
+ word-break: break-all;
120
+ }
121
+
122
+ .file-download {
123
+ color: #2196f3;
124
+ text-decoration: none;
125
+ font-size: 0.9em;
126
+ }
127
+
128
+ .file-download:hover {
129
+ text-decoration: underline;
130
+ }
131
+ </style>
@@ -0,0 +1,51 @@
1
+ module Deepagents
2
+ module Generators
3
+ class ControllerGenerator < Rails::Generators::NamedBase
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ desc "Creates DeepAgents API controllers for your Rails application"
7
+
8
+ class_option :skip_routes, type: :boolean, default: false, desc: "Skip routes generation"
9
+ class_option :api_version, type: :string, default: "v1", desc: "API version"
10
+
11
+ def create_controller_file
12
+ template "api_controller.rb", "app/controllers/api/#{options[:api_version]}/#{file_name}_controller.rb"
13
+ end
14
+
15
+ def create_serializer_file
16
+ template "serializer.rb", "app/serializers/#{file_name}_serializer.rb"
17
+ end
18
+
19
+ def add_routes
20
+ return if options[:skip_routes]
21
+
22
+ route_file = "config/routes.rb"
23
+ route_content = <<~ROUTE
24
+ namespace :api do
25
+ namespace :#{options[:api_version]} do
26
+ resources :#{plural_name}, only: [:index, :show, :create] do
27
+ member do
28
+ post :run
29
+ post :upload
30
+ end
31
+ end
32
+ end
33
+ end
34
+ ROUTE
35
+
36
+ inject_into_file route_file, route_content, after: "Rails.application.routes.draw do\n"
37
+ end
38
+
39
+ def display_next_steps
40
+ say "\n"
41
+ say "DeepAgents API controller for #{file_name} has been created! 🎮", :green
42
+ say "\n"
43
+ say "Next steps:", :yellow
44
+ say " 1. Ensure you have the required models (use the model generator if needed)"
45
+ say " 2. Add any custom API endpoints to your controller"
46
+ say " 3. Test your API endpoints with curl or Postman"
47
+ say "\n"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Api
4
+ module <%= options[:api_version].camelize %>
5
+ class <%= class_name %>Controller < ApplicationController
6
+ before_action :set_conversation, only: [:show, :run, :upload]
7
+
8
+ # GET /api/<%= options[:api_version] %>/<%= plural_name %>
9
+ def index
10
+ @conversations = Deepagents::<%= class_name %>Conversation.recent.limit(20)
11
+
12
+ render json: @conversations, each_serializer: <%= class_name %>Serializer
13
+ end
14
+
15
+ # GET /api/<%= options[:api_version] %>/<%= plural_name %>/:id
16
+ def show
17
+ render json: @conversation, serializer: <%= class_name %>Serializer, include: ['messages', 'files']
18
+ end
19
+
20
+ # POST /api/<%= options[:api_version] %>/<%= plural_name %>
21
+ def create
22
+ @conversation = Deepagents::<%= class_name %>Conversation.new(conversation_params)
23
+
24
+ if @conversation.save
25
+ # Add a system message if provided
26
+ if params[:system_message].present?
27
+ @conversation.<%= file_name %>_messages.create!(
28
+ role: 'system',
29
+ content: params[:system_message]
30
+ )
31
+ end
32
+
33
+ render json: @conversation, serializer: <%= class_name %>Serializer, status: :created
34
+ else
35
+ render json: { errors: @conversation.errors }, status: :unprocessable_entity
36
+ end
37
+ end
38
+
39
+ # POST /api/<%= options[:api_version] %>/<%= plural_name %>/:id/run
40
+ def run
41
+ input = params[:input]
42
+ agent_name = params[:agent_name]
43
+
44
+ if input.blank?
45
+ render json: { error: 'Input is required' }, status: :unprocessable_entity
46
+ return
47
+ end
48
+
49
+ result = @conversation.run_agent(input, agent_name)
50
+
51
+ render json: {
52
+ message: result[:message],
53
+ files: result[:files]
54
+ }
55
+ end
56
+
57
+ # POST /api/<%= options[:api_version] %>/<%= plural_name %>/:id/upload
58
+ def upload
59
+ if params[:file].blank?
60
+ render json: { error: 'File is required' }, status: :unprocessable_entity
61
+ return
62
+ end
63
+
64
+ file = params[:file]
65
+
66
+ @file = @conversation.<%= file_name %>_files.create!(
67
+ filename: file.original_filename,
68
+ content: file.read
69
+ )
70
+
71
+ render json: @file
72
+ end
73
+
74
+ private
75
+
76
+ def set_conversation
77
+ @conversation = Deepagents::<%= class_name %>Conversation.find(params[:id])
78
+ rescue ActiveRecord::RecordNotFound
79
+ render json: { error: 'Conversation not found' }, status: :not_found
80
+ end
81
+
82
+ def conversation_params
83
+ params.require(:<%= file_name %>).permit(:title, :agent_name, metadata: {})
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= class_name %>Serializer < ActiveModel::Serializer
4
+ attributes :id, :title, :agent_name, :metadata, :created_at, :updated_at
5
+
6
+ has_many :<%= file_name %>_messages, serializer: <%= class_name %>MessageSerializer
7
+ has_many :<%= file_name %>_files, serializer: <%= class_name %>FileSerializer
8
+
9
+ # Add any custom serialization logic here
10
+ end
11
+
12
+ class <%= class_name %>MessageSerializer < ActiveModel::Serializer
13
+ attributes :id, :role, :content, :metadata, :created_at
14
+ end
15
+
16
+ class <%= class_name %>FileSerializer < ActiveModel::Serializer
17
+ attributes :id, :filename, :content, :metadata, :created_at, :url
18
+
19
+ def url
20
+ object.url if object.respond_to?(:url)
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ module Deepagents
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ desc "Creates a DeepAgents initializer and necessary files for your Rails application"
7
+
8
+ def create_initializer_file
9
+ template "initializer.rb", "config/initializers/deepagents.rb"
10
+ end
11
+
12
+ def create_configuration_file
13
+ template "deepagents.yml", "config/deepagents.yml"
14
+ end
15
+
16
+ def mount_engine
17
+ route "mount DeepagentsRails::Engine => '/deepagents'"
18
+ end
19
+
20
+ def add_environment_variables
21
+ append_to_file '.env.example', <<~ENV
22
+
23
+ # DeepAgents configuration
24
+ # DEEPAGENTS_API_KEY=your_api_key_here
25
+ # DEEPAGENTS_PROVIDER=claude # or openai
26
+ ENV
27
+ end
28
+
29
+ def display_post_install_message
30
+ say "\n"
31
+ say "DeepAgents Rails has been installed! 🎉", :green
32
+ say "\n"
33
+ say "Next steps:", :yellow
34
+ say " 1. Configure your API keys in config/deepagents.yml or through environment variables"
35
+ say " 2. Generate your first agent with: rails g deepagents:agent NAME"
36
+ say " 3. Check out the documentation at https://github.com/cdaviis/deepagents_rails"
37
+ say "\n"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ # DeepAgents Rails Configuration
2
+
3
+ default: &default
4
+ # API key for your LLM provider (Claude or OpenAI)
5
+ # You can also set this via environment variable DEEPAGENTS_API_KEY
6
+ api_key: <%= ENV.fetch('DEEPAGENTS_API_KEY', nil) %>
7
+
8
+ # LLM provider to use (claude or openai)
9
+ provider: <%= ENV.fetch('DEEPAGENTS_PROVIDER', 'claude') %>
10
+
11
+ # Default model to use
12
+ model: <%= ENV.fetch('DEEPAGENTS_MODEL', 'claude-3-sonnet-20240229') %>
13
+
14
+ # Default temperature for LLM requests (0.0 to 1.0)
15
+ temperature: <%= ENV.fetch('DEEPAGENTS_TEMPERATURE', '0.7') %>
16
+
17
+ # Maximum tokens to generate in responses
18
+ max_tokens: <%= ENV.fetch('DEEPAGENTS_MAX_TOKENS', '4096') %>
19
+
20
+ # Default tools available to all agents
21
+ default_tools:
22
+ - calculator
23
+ - file_system
24
+ - planning
25
+
26
+ development:
27
+ <<: *default
28
+ log_requests: true
29
+
30
+ test:
31
+ <<: *default
32
+ # Use mock model for testing
33
+ provider: mock
34
+ model: mock-model
35
+
36
+ production:
37
+ <<: *default
38
+ log_requests: false
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # DeepAgents Rails configuration
4
+ DeepagentsRails::Engine.config.deepagents.tap do |config|
5
+ # API key for your LLM provider (Claude or OpenAI)
6
+ # You can set this via environment variable DEEPAGENTS_API_KEY
7
+ config.api_key = ENV.fetch('DEEPAGENTS_API_KEY', nil)
8
+
9
+ # LLM provider to use (:claude or :openai)
10
+ # You can set this via environment variable DEEPAGENTS_PROVIDER
11
+ config.provider = ENV.fetch('DEEPAGENTS_PROVIDER', 'claude').to_sym
12
+
13
+ # Default model to use
14
+ # For Claude: "claude-3-sonnet-20240229", "claude-3-opus-20240229", etc.
15
+ # For OpenAI: "gpt-4o", "gpt-4-turbo", etc.
16
+ config.model = ENV.fetch('DEEPAGENTS_MODEL', 'claude-3-sonnet-20240229')
17
+
18
+ # Default temperature for LLM requests (0.0 to 1.0)
19
+ config.temperature = ENV.fetch('DEEPAGENTS_TEMPERATURE', '0.7').to_f
20
+
21
+ # Maximum tokens to generate in responses
22
+ config.max_tokens = ENV.fetch('DEEPAGENTS_MAX_TOKENS', '4096').to_i
23
+
24
+ # Configure default tools available to all agents
25
+ # config.default_tools = [:calculator, :web_search]
26
+
27
+ # Configure logging
28
+ config.log_requests = Rails.env.development?
29
+ end
30
+
31
+ # Load custom tools
32
+ # Dir[Rails.root.join('app/deepagents/tools/**/*.rb')].each { |file| require file }
33
+
34
+ # Load custom agents
35
+ # Dir[Rails.root.join('app/deepagents/agents/**/*.rb')].each { |file| require file }
@@ -0,0 +1,43 @@
1
+ module Deepagents
2
+ module Generators
3
+ class ModelGenerator < Rails::Generators::NamedBase
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ desc "Creates DeepAgents models for your Rails application"
7
+
8
+ def create_conversation_model
9
+ template "conversation.rb", "app/models/deepagents/#{file_name}_conversation.rb"
10
+ end
11
+
12
+ def create_message_model
13
+ template "message.rb", "app/models/deepagents/#{file_name}_message.rb"
14
+ end
15
+
16
+ def create_file_model
17
+ template "file.rb", "app/models/deepagents/#{file_name}_file.rb"
18
+ end
19
+
20
+ def create_migrations
21
+ template "create_conversations_migration.rb", "db/migrate/#{timestamp}_create_deepagents_#{file_name}_conversations.rb"
22
+ template "create_messages_migration.rb", "db/migrate/#{timestamp(1)}_create_deepagents_#{file_name}_messages.rb"
23
+ template "create_files_migration.rb", "db/migrate/#{timestamp(2)}_create_deepagents_#{file_name}_files.rb"
24
+ end
25
+
26
+ def display_next_steps
27
+ say "\n"
28
+ say "DeepAgents models for #{file_name} have been created! 📚", :green
29
+ say "\n"
30
+ say "Next steps:", :yellow
31
+ say " 1. Run migrations with: rails db:migrate"
32
+ say " 2. Use the models in your agents and controllers"
33
+ say "\n"
34
+ end
35
+
36
+ private
37
+
38
+ def timestamp(offset = 0)
39
+ Time.now.utc.strftime("%Y%m%d%H%M%S").to_i + offset
40
+ end
41
+ end
42
+ end
43
+ end