rails_ai_agents 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/MIT-LICENSE +20 -0
- data/README.md +296 -0
- data/Rakefile +14 -0
- data/app/models/ai_agents/agent.rb +61 -0
- data/app/services/ai_agents/llm_client.rb +91 -0
- data/lib/generators/ai_agents/install/install_generator.rb +36 -0
- data/lib/generators/ai_agents/install/templates/README +33 -0
- data/lib/generators/ai_agents/install/templates/ai_agents_initializer.rb.erb +15 -0
- data/lib/generators/ai_agents/install/templates/create_ai_agents.rb.erb +16 -0
- data/lib/rails_ai_agents/engine.rb +28 -0
- data/lib/rails_ai_agents/tasks/ai_agents.rake +62 -0
- data/lib/rails_ai_agents/version.rb +3 -0
- data/lib/rails_ai_agents.rb +30 -0
- metadata +145 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c25238542baeaaf8282355331fe4cbf48e7cf7f9599b08e99ac72482377d3af5
|
|
4
|
+
data.tar.gz: 592c3a6f26984a0b42580630cbdad218a2ab205b1248e644b34f7b10ed132554
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: efef1eedec187ecd9e5ee3860decefb394d76b42de5a15f64deb07bc2b12e4b5021071ca88d6407b2cbc0a05cef7caf1efe104b0a219a392539c648e6e877639
|
|
7
|
+
data.tar.gz: d9baafe0f8124cc75e65d58da83bb9ce41b2273bce72a7f560a58341b566ec63803092e81b9d1fb71600939afafe2b00a07cf608735b634068b8b11c681778fb
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2024 Rohit
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# Rails AI Agents
|
|
2
|
+
|
|
3
|
+
A modular and extendable Rails engine that provides an Agent model and LLM client integration for building AI-powered applications.
|
|
4
|
+
|
|
5
|
+
[](https://www.ruby-lang.org/en/)
|
|
6
|
+
[](https://rubyonrails.org/)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🚀 **Mountable Rails Engine** - Easily integrate into existing Rails applications
|
|
11
|
+
- 🤖 **Agent Model** - Manage AI agents with configurable settings
|
|
12
|
+
- 🔌 **LLM Integration** - Built-in support for OpenAI and other LLM providers
|
|
13
|
+
- ⚙️ **Configurable** - Flexible configuration through Rails initializers
|
|
14
|
+
- 🛠️ **Generator Support** - Easy installation with Rails generators
|
|
15
|
+
- 📋 **Rake Tasks** - Built-in commands for managing agents
|
|
16
|
+
- 🔄 **Extensible** - Modular design for easy customization
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- Ruby >= 3.2.0
|
|
21
|
+
- Rails >= 8.0.0
|
|
22
|
+
- A supported LLM provider (OpenAI, etc.)
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
Add this line to your application's Gemfile:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
gem 'rails_ai_agents'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
And then execute:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bundle install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or install it yourself as:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gem install rails_ai_agents
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Setup
|
|
45
|
+
|
|
46
|
+
### 1. Run the installer
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
rails generate ai_agents:install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This will:
|
|
53
|
+
- Create a migration for the `ai_agents` table
|
|
54
|
+
- Generate a configuration initializer at `config/initializers/ai_agents.rb`
|
|
55
|
+
|
|
56
|
+
### 2. Run the migration
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
rails db:migrate
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Configure your LLM provider
|
|
63
|
+
|
|
64
|
+
Edit `config/initializers/ai_agents.rb`:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
RailsAiAgents.configure do |config|
|
|
68
|
+
# LLM Provider Configuration
|
|
69
|
+
config.llm_provider = :openai
|
|
70
|
+
|
|
71
|
+
# API Key (store securely!)
|
|
72
|
+
config.api_key = Rails.application.credentials.openai_api_key || ENV['OPENAI_API_KEY']
|
|
73
|
+
|
|
74
|
+
# Default model
|
|
75
|
+
config.default_model = "gpt-3.5-turbo"
|
|
76
|
+
|
|
77
|
+
# API base URL (for OpenAI-compatible APIs)
|
|
78
|
+
config.api_base_url = "https://api.openai.com/v1"
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 4. Test your configuration
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
rails ai_agents:test_connection
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
### Creating Agents
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
# Create a basic agent
|
|
94
|
+
agent = AiAgents::Agent.create!(
|
|
95
|
+
name: "Assistant",
|
|
96
|
+
description: "A helpful AI assistant",
|
|
97
|
+
model: "gpt-3.5-turbo"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Create an agent with custom configuration
|
|
101
|
+
agent = AiAgents::Agent.create!(
|
|
102
|
+
name: "Creative Writer",
|
|
103
|
+
description: "An AI specialized in creative writing",
|
|
104
|
+
model: "gpt-4",
|
|
105
|
+
config: {
|
|
106
|
+
"temperature" => 0.9,
|
|
107
|
+
"max_tokens" => 2000,
|
|
108
|
+
"top_p" => 0.95
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Using Agents
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
# Simple usage
|
|
117
|
+
agent = AiAgents::Agent.find_by(name: "Assistant")
|
|
118
|
+
response = agent.run("Hello, how are you today?")
|
|
119
|
+
puts response
|
|
120
|
+
|
|
121
|
+
# Handle errors
|
|
122
|
+
begin
|
|
123
|
+
response = agent.run("Write a story about robots")
|
|
124
|
+
puts response
|
|
125
|
+
rescue AiAgents::LLMClient::AuthenticationError => e
|
|
126
|
+
puts "Authentication failed: #{e.message}"
|
|
127
|
+
rescue AiAgents::LLMClient::RateLimitError => e
|
|
128
|
+
puts "Rate limit exceeded: #{e.message}"
|
|
129
|
+
rescue AiAgents::LLMClient::APIError => e
|
|
130
|
+
puts "API error: #{e.message}"
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Finding Agents
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
# Find by name
|
|
138
|
+
agent = AiAgents::Agent.by_name("Assistant")
|
|
139
|
+
|
|
140
|
+
# Find active agents
|
|
141
|
+
active_agents = AiAgents::Agent.active
|
|
142
|
+
|
|
143
|
+
# Find agents by model
|
|
144
|
+
gpt4_agents = AiAgents::Agent.where(model: "gpt-4")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Managing Agents
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
# List all agents (via rake task)
|
|
151
|
+
rails ai_agents:list
|
|
152
|
+
|
|
153
|
+
# Deactivate an agent
|
|
154
|
+
agent.update!(active: false)
|
|
155
|
+
|
|
156
|
+
# Update agent configuration
|
|
157
|
+
agent.update!(
|
|
158
|
+
config: {
|
|
159
|
+
"temperature" => 0.5,
|
|
160
|
+
"max_tokens" => 1500
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
The gem supports the following configuration options:
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
RailsAiAgents.configure do |config|
|
|
171
|
+
# LLM Provider (:openai is currently the only supported provider)
|
|
172
|
+
config.llm_provider = :openai
|
|
173
|
+
|
|
174
|
+
# Your API key
|
|
175
|
+
config.api_key = "your-api-key-here"
|
|
176
|
+
|
|
177
|
+
# Default model to use for new agents
|
|
178
|
+
config.default_model = "gpt-3.5-turbo"
|
|
179
|
+
|
|
180
|
+
# API base URL (useful for OpenAI-compatible APIs)
|
|
181
|
+
config.api_base_url = "https://api.openai.com/v1"
|
|
182
|
+
end
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Agent Configuration Options
|
|
186
|
+
|
|
187
|
+
Each agent can be configured with the following options in their `config` field:
|
|
188
|
+
|
|
189
|
+
- `temperature`: Controls randomness (0.0 to 2.0, default: 0.7)
|
|
190
|
+
- `max_tokens`: Maximum tokens in response (default: 1000)
|
|
191
|
+
- `top_p`: Nucleus sampling parameter (0.0 to 1.0, default: 1.0)
|
|
192
|
+
- `frequency_penalty`: Reduces repetition (-2.0 to 2.0, default: 0.0)
|
|
193
|
+
- `presence_penalty`: Encourages new topics (-2.0 to 2.0, default: 0.0)
|
|
194
|
+
|
|
195
|
+
## Rake Tasks
|
|
196
|
+
|
|
197
|
+
### List all agents
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
rails ai_agents:list
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Shows all registered agents with their configurations and status.
|
|
204
|
+
|
|
205
|
+
### Test LLM connection
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
rails ai_agents:test_connection
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Tests the connection to your configured LLM provider.
|
|
212
|
+
|
|
213
|
+
## Routes
|
|
214
|
+
|
|
215
|
+
This gem is designed as a mountable engine but **does not auto-mount any routes**. You have full control over the routing in your host application.
|
|
216
|
+
|
|
217
|
+
If you want to add web interfaces for managing agents, you can create controllers in your host app or mount specific routes as needed.
|
|
218
|
+
|
|
219
|
+
## Error Handling
|
|
220
|
+
|
|
221
|
+
The gem provides several custom exception classes:
|
|
222
|
+
|
|
223
|
+
- `AiAgents::LLMClient::LLMError` - Base error class
|
|
224
|
+
- `AiAgents::LLMClient::AuthenticationError` - API key issues
|
|
225
|
+
- `AiAgents::LLMClient::RateLimitError` - Rate limiting
|
|
226
|
+
- `AiAgents::LLMClient::APIError` - General API errors
|
|
227
|
+
|
|
228
|
+
## Extending the Gem
|
|
229
|
+
|
|
230
|
+
### Adding Custom LLM Providers
|
|
231
|
+
|
|
232
|
+
To add support for additional LLM providers, extend the `LLMClient` class:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
# In your application
|
|
236
|
+
module AiAgents
|
|
237
|
+
class LLMClient
|
|
238
|
+
private
|
|
239
|
+
|
|
240
|
+
def complete_with_custom_provider(prompt)
|
|
241
|
+
# Your custom implementation
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Custom Agent Behaviors
|
|
248
|
+
|
|
249
|
+
You can extend the `Agent` model in your application:
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
# app/models/ai_agents/agent.rb (in your app)
|
|
253
|
+
module AiAgents
|
|
254
|
+
class Agent
|
|
255
|
+
# Add custom methods or behaviors
|
|
256
|
+
def run_with_context(prompt, context = {})
|
|
257
|
+
enhanced_prompt = "Context: #{context.to_json}\n\nPrompt: #{prompt}"
|
|
258
|
+
run(enhanced_prompt)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Database Schema
|
|
265
|
+
|
|
266
|
+
The `ai_agents` table includes:
|
|
267
|
+
|
|
268
|
+
- `name` - Unique identifier for the agent
|
|
269
|
+
- `description` - Human-readable description
|
|
270
|
+
- `model` - LLM model to use (e.g., "gpt-3.5-turbo")
|
|
271
|
+
- `config` - JSON configuration for model parameters
|
|
272
|
+
- `active` - Boolean flag for enabling/disabling agents
|
|
273
|
+
- `created_at` / `updated_at` - Standard Rails timestamps
|
|
274
|
+
|
|
275
|
+
## Security Considerations
|
|
276
|
+
|
|
277
|
+
1. **API Keys**: Store API keys securely using Rails credentials or environment variables
|
|
278
|
+
2. **Input Validation**: Always validate and sanitize user inputs before sending to LLM APIs
|
|
279
|
+
3. **Rate Limiting**: Implement rate limiting in your application to avoid API limits
|
|
280
|
+
4. **Cost Control**: Monitor your LLM provider usage to control costs
|
|
281
|
+
|
|
282
|
+
## Contributing
|
|
283
|
+
|
|
284
|
+
1. Fork the repository
|
|
285
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
286
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
287
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
288
|
+
5. Open a Pull Request
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
This gem is available as open source under the terms of the [MIT License](MIT-LICENSE).
|
|
293
|
+
|
|
294
|
+
## Changelog
|
|
295
|
+
|
|
296
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history and changes.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rspec/core/rake_task"
|
|
3
|
+
|
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
5
|
+
|
|
6
|
+
task default: :spec
|
|
7
|
+
|
|
8
|
+
# Load engine rake tasks in development
|
|
9
|
+
begin
|
|
10
|
+
require 'rails_ai_agents/engine'
|
|
11
|
+
RailsAiAgents::Engine.load_tasks
|
|
12
|
+
rescue LoadError
|
|
13
|
+
# Engine not loaded in development
|
|
14
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module AiAgents
|
|
2
|
+
class Agent < ApplicationRecord
|
|
3
|
+
self.table_name = "ai_agents"
|
|
4
|
+
|
|
5
|
+
# Validations
|
|
6
|
+
validates :name, presence: true, uniqueness: true
|
|
7
|
+
validates :description, presence: true
|
|
8
|
+
validates :model, presence: true
|
|
9
|
+
|
|
10
|
+
# JSON serialization for config field
|
|
11
|
+
serialize :config, coder: JSON
|
|
12
|
+
|
|
13
|
+
# Callbacks
|
|
14
|
+
before_validation :set_default_config, if: -> { config.blank? }
|
|
15
|
+
before_validation :set_default_model, if: -> { model.blank? }
|
|
16
|
+
|
|
17
|
+
# Instance methods
|
|
18
|
+
def run(prompt)
|
|
19
|
+
raise ArgumentError, "Prompt cannot be blank" if prompt.blank?
|
|
20
|
+
|
|
21
|
+
llm_client = AiAgents::LLMClient.new(
|
|
22
|
+
model: self.model,
|
|
23
|
+
config: self.config
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
llm_client.complete(prompt)
|
|
27
|
+
rescue => e
|
|
28
|
+
Rails.logger.error "Agent #{name} failed to process prompt: #{e.message}"
|
|
29
|
+
raise e
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Class methods
|
|
33
|
+
def self.by_name(name)
|
|
34
|
+
find_by(name: name)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.active
|
|
38
|
+
where(active: true)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def set_default_config
|
|
44
|
+
self.config = default_config
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def set_default_model
|
|
48
|
+
self.model = RailsAiAgents.configuration.default_model
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def default_config
|
|
52
|
+
{
|
|
53
|
+
"temperature" => 0.7,
|
|
54
|
+
"max_tokens" => 1000,
|
|
55
|
+
"top_p" => 1.0,
|
|
56
|
+
"frequency_penalty" => 0.0,
|
|
57
|
+
"presence_penalty" => 0.0
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require "faraday"
|
|
2
|
+
require "json"
|
|
3
|
+
|
|
4
|
+
module AiAgents
|
|
5
|
+
class LLMClient
|
|
6
|
+
class LLMError < StandardError; end
|
|
7
|
+
class AuthenticationError < LLMError; end
|
|
8
|
+
class RateLimitError < LLMError; end
|
|
9
|
+
class APIError < LLMError; end
|
|
10
|
+
|
|
11
|
+
attr_reader :model, :config
|
|
12
|
+
|
|
13
|
+
def initialize(model: nil, config: {})
|
|
14
|
+
@model = model || RailsAiAgents.configuration.default_model
|
|
15
|
+
@config = config || {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def complete(prompt)
|
|
19
|
+
case RailsAiAgents.configuration.llm_provider
|
|
20
|
+
when :openai
|
|
21
|
+
complete_with_openai(prompt)
|
|
22
|
+
else
|
|
23
|
+
raise LLMError, "Unsupported LLM provider: #{RailsAiAgents.configuration.llm_provider}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def complete_with_openai(prompt)
|
|
30
|
+
raise AuthenticationError, "OpenAI API key not configured" unless api_key
|
|
31
|
+
|
|
32
|
+
response = openai_client.post("/chat/completions") do |req|
|
|
33
|
+
req.headers["Authorization"] = "Bearer #{api_key}"
|
|
34
|
+
req.headers["Content-Type"] = "application/json"
|
|
35
|
+
req.body = build_openai_payload(prompt).to_json
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
handle_openai_response(response)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build_openai_payload(prompt)
|
|
42
|
+
{
|
|
43
|
+
model: @model,
|
|
44
|
+
messages: [
|
|
45
|
+
{
|
|
46
|
+
role: "user",
|
|
47
|
+
content: prompt
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
temperature: @config["temperature"] || 0.7,
|
|
51
|
+
max_tokens: @config["max_tokens"] || 1000,
|
|
52
|
+
top_p: @config["top_p"] || 1.0,
|
|
53
|
+
frequency_penalty: @config["frequency_penalty"] || 0.0,
|
|
54
|
+
presence_penalty: @config["presence_penalty"] || 0.0
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def handle_openai_response(response)
|
|
59
|
+
case response.status
|
|
60
|
+
when 200
|
|
61
|
+
data = JSON.parse(response.body)
|
|
62
|
+
data.dig("choices", 0, "message", "content")
|
|
63
|
+
when 401
|
|
64
|
+
raise AuthenticationError, "Invalid API key"
|
|
65
|
+
when 429
|
|
66
|
+
raise RateLimitError, "Rate limit exceeded"
|
|
67
|
+
when 400..499
|
|
68
|
+
error_data = JSON.parse(response.body) rescue {}
|
|
69
|
+
error_message = error_data.dig("error", "message") || "Client error"
|
|
70
|
+
raise APIError, "Client error: #{error_message}"
|
|
71
|
+
when 500..599
|
|
72
|
+
raise APIError, "Server error: #{response.status}"
|
|
73
|
+
else
|
|
74
|
+
raise APIError, "Unexpected response: #{response.status}"
|
|
75
|
+
end
|
|
76
|
+
rescue JSON::ParserError => e
|
|
77
|
+
raise APIError, "Invalid JSON response: #{e.message}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def openai_client
|
|
81
|
+
@openai_client ||= Faraday.new(
|
|
82
|
+
url: RailsAiAgents.configuration.api_base_url,
|
|
83
|
+
request: { timeout: 30 }
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def api_key
|
|
88
|
+
@api_key ||= RailsAiAgents.configuration.api_key
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/migration"
|
|
3
|
+
|
|
4
|
+
module AiAgents
|
|
5
|
+
module Generators
|
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
|
7
|
+
include Rails::Generators::Migration
|
|
8
|
+
|
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
|
+
desc "Install AI Agents migration and initializer"
|
|
11
|
+
|
|
12
|
+
def self.next_migration_number(path)
|
|
13
|
+
next_migration_number = current_migration_number(path) + 1
|
|
14
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def copy_migration
|
|
18
|
+
migration_template "create_ai_agents.rb.erb", "db/migrate/create_ai_agents.rb"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def copy_initializer
|
|
22
|
+
template "ai_agents_initializer.rb.erb", "config/initializers/ai_agents.rb"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def show_readme
|
|
26
|
+
readme "README" if behavior == :invoke
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def migration_version
|
|
32
|
+
"[#{ActiveRecord::Migration.current_version}]"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
===============================================================================
|
|
2
|
+
|
|
3
|
+
Rails AI Agents has been installed!
|
|
4
|
+
|
|
5
|
+
===============================================================================
|
|
6
|
+
|
|
7
|
+
Next steps:
|
|
8
|
+
|
|
9
|
+
1. Run the migration to create the ai_agents table:
|
|
10
|
+
rails db:migrate
|
|
11
|
+
|
|
12
|
+
2. Configure your LLM provider in config/initializers/ai_agents.rb
|
|
13
|
+
Make sure to set your API key using Rails credentials or environment variables.
|
|
14
|
+
|
|
15
|
+
3. Create your first AI agent:
|
|
16
|
+
|
|
17
|
+
agent = AiAgents::Agent.create!(
|
|
18
|
+
name: "Assistant",
|
|
19
|
+
description: "A helpful assistant",
|
|
20
|
+
model: "gpt-3.5-turbo"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
4. Use your agent:
|
|
24
|
+
|
|
25
|
+
response = agent.run("Hello, how are you?")
|
|
26
|
+
puts response
|
|
27
|
+
|
|
28
|
+
5. List all agents using the rake task:
|
|
29
|
+
rails ai_agents:list
|
|
30
|
+
|
|
31
|
+
For more information, check out the documentation.
|
|
32
|
+
|
|
33
|
+
===============================================================================
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
RailsAiAgents.configure do |config|
|
|
2
|
+
# LLM Provider Configuration
|
|
3
|
+
# Supported providers: :openai (more coming soon)
|
|
4
|
+
config.llm_provider = :openai
|
|
5
|
+
|
|
6
|
+
# API Key for your LLM provider
|
|
7
|
+
# It's recommended to store this in Rails credentials or environment variables
|
|
8
|
+
config.api_key = Rails.application.credentials.openai_api_key || ENV['OPENAI_API_KEY']
|
|
9
|
+
|
|
10
|
+
# Default model to use if not specified on individual agents
|
|
11
|
+
config.default_model = "gpt-3.5-turbo"
|
|
12
|
+
|
|
13
|
+
# API base URL (useful for OpenAI-compatible APIs)
|
|
14
|
+
config.api_base_url = "https://api.openai.com/v1"
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateAiAgents < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
+
def change
|
|
3
|
+
create_table :ai_agents do |t|
|
|
4
|
+
t.string :name, null: false, index: { unique: true }
|
|
5
|
+
t.text :description, null: false
|
|
6
|
+
t.string :model, null: false
|
|
7
|
+
t.json :config, default: {}
|
|
8
|
+
t.boolean :active, default: true, null: false
|
|
9
|
+
|
|
10
|
+
t.timestamps null: false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_index :ai_agents, :active
|
|
14
|
+
add_index :ai_agents, :model
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "rails/engine"
|
|
2
|
+
|
|
3
|
+
module RailsAiAgents
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace RailsAiAgents
|
|
6
|
+
|
|
7
|
+
# Don't auto-mount any routes - let the host app define them
|
|
8
|
+
config.generators do |g|
|
|
9
|
+
g.test_framework :rspec, fixture: false
|
|
10
|
+
g.fixture_replacement :factory_bot, dir: "spec/factories"
|
|
11
|
+
g.assets false
|
|
12
|
+
g.helper false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Load rake tasks
|
|
16
|
+
rake_tasks do
|
|
17
|
+
load File.expand_path("../tasks/ai_agents.rake", __dir__)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Ensure models and services are autoloaded
|
|
21
|
+
config.autoload_paths << File.expand_path("../../app/models", __dir__)
|
|
22
|
+
config.autoload_paths << File.expand_path("../../app/services", __dir__)
|
|
23
|
+
|
|
24
|
+
initializer "rails_ai_agents.load_app_root" do |app|
|
|
25
|
+
config.paths.add "config/database", with: "config/database.yml"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
namespace :ai_agents do
|
|
2
|
+
desc "List all registered AI agents"
|
|
3
|
+
task list: :environment do
|
|
4
|
+
begin
|
|
5
|
+
agents = AiAgents::Agent.all.order(:name)
|
|
6
|
+
|
|
7
|
+
if agents.empty?
|
|
8
|
+
puts "No AI agents found. Create one using AiAgents::Agent.create!"
|
|
9
|
+
puts
|
|
10
|
+
puts "Example:"
|
|
11
|
+
puts " agent = AiAgents::Agent.create!("
|
|
12
|
+
puts " name: 'Assistant',"
|
|
13
|
+
puts " description: 'A helpful assistant',"
|
|
14
|
+
puts " model: 'gpt-3.5-turbo'"
|
|
15
|
+
puts " )"
|
|
16
|
+
else
|
|
17
|
+
puts "AI Agents (#{agents.count} total):"
|
|
18
|
+
puts "=" * 60
|
|
19
|
+
|
|
20
|
+
agents.each do |agent|
|
|
21
|
+
status = agent.active? ? "✓ Active" : "✗ Inactive"
|
|
22
|
+
|
|
23
|
+
puts "Name: #{agent.name}"
|
|
24
|
+
puts "Description: #{agent.description}"
|
|
25
|
+
puts "Model: #{agent.model}"
|
|
26
|
+
puts "Status: #{status}"
|
|
27
|
+
puts "Created: #{agent.created_at.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
28
|
+
puts "Config: #{agent.config.inspect}" if agent.config.present?
|
|
29
|
+
puts "-" * 40
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
rescue => e
|
|
33
|
+
puts "Error listing agents: #{e.message}"
|
|
34
|
+
puts "Make sure you've run 'rails ai_agents:install' and 'rails db:migrate'"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Test connection to LLM provider"
|
|
39
|
+
task test_connection: :environment do
|
|
40
|
+
begin
|
|
41
|
+
puts "Testing connection to #{RailsAiAgents.configuration.llm_provider}..."
|
|
42
|
+
puts "Model: #{RailsAiAgents.configuration.default_model}"
|
|
43
|
+
puts "API Base URL: #{RailsAiAgents.configuration.api_base_url}"
|
|
44
|
+
|
|
45
|
+
if RailsAiAgents.configuration.api_key.nil?
|
|
46
|
+
puts "❌ API key not configured"
|
|
47
|
+
puts "Set your API key in config/initializers/ai_agents.rb"
|
|
48
|
+
else
|
|
49
|
+
puts "✅ API key is configured"
|
|
50
|
+
|
|
51
|
+
# Test with a simple prompt
|
|
52
|
+
client = AiAgents::LLMClient.new
|
|
53
|
+
response = client.complete("Say 'Hello from Rails AI Agents!'")
|
|
54
|
+
|
|
55
|
+
puts "✅ Connection successful!"
|
|
56
|
+
puts "Response: #{response}"
|
|
57
|
+
end
|
|
58
|
+
rescue => e
|
|
59
|
+
puts "❌ Connection failed: #{e.message}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require "rails_ai_agents/version"
|
|
2
|
+
require "rails_ai_agents/engine"
|
|
3
|
+
|
|
4
|
+
module RailsAiAgents
|
|
5
|
+
# Configuration class for gem-wide settings
|
|
6
|
+
class Configuration
|
|
7
|
+
attr_accessor :llm_provider, :api_key, :default_model, :api_base_url
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@llm_provider = :openai
|
|
11
|
+
@api_key = nil
|
|
12
|
+
@default_model = "gpt-3.5-turbo"
|
|
13
|
+
@api_base_url = "https://api.openai.com/v1"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
def configuration
|
|
19
|
+
@configuration ||= Configuration.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def configure
|
|
23
|
+
yield(configuration)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def reset_configuration!
|
|
27
|
+
@configuration = Configuration.new
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails_ai_agents
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Rohit
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-10-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 8.0.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 8.0.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: faraday-multipart
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: sqlite3
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.4'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.4'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec-rails
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '6.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '6.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: factory_bot_rails
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '6.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '6.0'
|
|
97
|
+
description: A modular and extendable Rails engine that provides an Agent model and
|
|
98
|
+
LLM client integration for building AI-powered applications.
|
|
99
|
+
email:
|
|
100
|
+
- your-email@example.com
|
|
101
|
+
executables: []
|
|
102
|
+
extensions: []
|
|
103
|
+
extra_rdoc_files: []
|
|
104
|
+
files:
|
|
105
|
+
- MIT-LICENSE
|
|
106
|
+
- README.md
|
|
107
|
+
- Rakefile
|
|
108
|
+
- app/models/ai_agents/agent.rb
|
|
109
|
+
- app/services/ai_agents/llm_client.rb
|
|
110
|
+
- lib/generators/ai_agents/install/install_generator.rb
|
|
111
|
+
- lib/generators/ai_agents/install/templates/README
|
|
112
|
+
- lib/generators/ai_agents/install/templates/ai_agents_initializer.rb.erb
|
|
113
|
+
- lib/generators/ai_agents/install/templates/create_ai_agents.rb.erb
|
|
114
|
+
- lib/rails_ai_agents.rb
|
|
115
|
+
- lib/rails_ai_agents/engine.rb
|
|
116
|
+
- lib/rails_ai_agents/tasks/ai_agents.rake
|
|
117
|
+
- lib/rails_ai_agents/version.rb
|
|
118
|
+
homepage: https://github.com/yourusername/rails_ai_agents
|
|
119
|
+
licenses:
|
|
120
|
+
- MIT
|
|
121
|
+
metadata:
|
|
122
|
+
allowed_push_host: https://rubygems.org
|
|
123
|
+
homepage_uri: https://github.com/yourusername/rails_ai_agents
|
|
124
|
+
source_code_uri: https://github.com/yourusername/rails_ai_agents
|
|
125
|
+
changelog_uri: https://github.com/yourusername/rails_ai_agents/CHANGELOG.md
|
|
126
|
+
post_install_message:
|
|
127
|
+
rdoc_options: []
|
|
128
|
+
require_paths:
|
|
129
|
+
- lib
|
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
|
+
requirements:
|
|
132
|
+
- - ">="
|
|
133
|
+
- !ruby/object:Gem::Version
|
|
134
|
+
version: 3.2.0
|
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
|
+
requirements:
|
|
137
|
+
- - ">="
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: 1.8.11
|
|
140
|
+
requirements: []
|
|
141
|
+
rubygems_version: 3.4.10
|
|
142
|
+
signing_key:
|
|
143
|
+
specification_version: 4
|
|
144
|
+
summary: A Rails engine for managing AI agents with LLM integration
|
|
145
|
+
test_files: []
|