rails_ai 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +310 -0
- data/lib/rails_ai/version.rb +1 -1
- data/lib/rails_ai.rb +169 -362
- data/setup_wiki.sh +55 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3462b92ede383e82fc730daa4a03aab2e25c03afde4d269345744658b726d39
|
4
|
+
data.tar.gz: 4e0d4a89fe63816f4f91e1782fa03c6a4eec49db2f7820216bf6aaf6d659604b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4008bd2db4e5e0770c9847570e0db636dcdbb70a27adf6a4c941af33a2e63535b5f70fb341f93f1f12ca548e2e597b667bb4307851344c7a6497034f1c1f0f96
|
7
|
+
data.tar.gz: 1336af819a3971b20bf6570234ac73bf98796ae7a487cbe7a1b4d0b8a87a7f6e92c40b73478cd38b36487384cf6760df8ca38c245585b9f2d61a75f6f74b8efb
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to the Rails AI gem will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [0.2.3] - 2024-09-21
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
- Fixed `create_agent_team` method to use correct parameter name (`collaboration_strategy` instead of `strategy`)
|
12
|
+
- Resolved `ArgumentError: unknown keyword: :strategy` in agent team creation
|
13
|
+
- Improved agent task execution to return meaningful AI-generated results instead of just task confirmation
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
- Updated agent demo to show actual AI responses from collaborative agent work
|
17
|
+
- Enhanced agent controller to simulate multi-agent collaboration with specialized prompts
|
18
|
+
|
19
|
+
## [0.2.2] - 2024-09-21
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
- Fixed streaming demo EventSource MIME type error by properly handling GET requests for Server-Sent Events
|
23
|
+
- Resolved `CookieOverflow` error by implementing file-based storage for large AI responses
|
24
|
+
- Fixed compressed response display by adding Zlib decompression in streaming controller
|
25
|
+
- Updated streaming view to handle plain text responses instead of expecting JSON
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
- Improved streaming response handling with proper decompression of compressed chunks
|
29
|
+
- Enhanced error handling for streaming connections
|
30
|
+
- Updated demo controller to use file storage instead of session for large responses
|
31
|
+
|
32
|
+
## [0.2.1] - 2024-09-21
|
33
|
+
|
34
|
+
### Added
|
35
|
+
- Web search integration with `WebSearch` module supporting Google Search and DuckDuckGo
|
36
|
+
- `chat_with_web_search` method for real-time information retrieval
|
37
|
+
- Support for current, latest, today, now, recent, weather, news, stock, price keywords
|
38
|
+
- Web search fallback to regular chat if search fails
|
39
|
+
|
40
|
+
### Fixed
|
41
|
+
- Fixed `ArgumentError: unknown keyword: :num_results` in web search integration
|
42
|
+
- Resolved method visibility issues with `validate_messages` method
|
43
|
+
- Fixed file loading conflicts between duplicate `InputValidator` classes
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
- Updated demo app to use GPT-4o instead of non-existent GPT-5
|
47
|
+
- Enhanced chat demo with web search checkbox option
|
48
|
+
- Improved error handling for web search failures
|
49
|
+
|
50
|
+
## [0.2.0] - 2024-09-21
|
51
|
+
|
52
|
+
### Added
|
53
|
+
- Comprehensive security framework with input validation, rate limiting, and content sanitization
|
54
|
+
- Secure HTTP client with SSL/TLS enforcement and security headers
|
55
|
+
- API key management with encryption and secure storage
|
56
|
+
- SSRF protection and secure file handling
|
57
|
+
- Audit logging for security events
|
58
|
+
- Custom security scanner with vulnerability detection
|
59
|
+
- CI/CD security monitoring with multiple security tools
|
60
|
+
|
61
|
+
### Fixed
|
62
|
+
- Fixed syntax error with extra `end` keyword in main module
|
63
|
+
- Resolved character encoding issues with UTF-8 conversion
|
64
|
+
- Fixed method visibility and file loading conflicts
|
65
|
+
|
66
|
+
### Security
|
67
|
+
- Implemented input validation for text, file paths, URLs, and Base64 data
|
68
|
+
- Added rate limiting per user and endpoint
|
69
|
+
- Content sanitization to prevent XSS and injection attacks
|
70
|
+
- Secure file handling with path validation and size limits
|
71
|
+
- API security with SSL/TLS enforcement and error handling
|
72
|
+
- SSRF protection with URL validation and host blocking
|
73
|
+
|
74
|
+
## [0.1.9] - 2024-09-21
|
75
|
+
|
76
|
+
### Fixed
|
77
|
+
- Fixed CI validation errors by excluding `.gem` files from gemspec
|
78
|
+
- Resolved `NoMethodError: undefined method 'megabytes'` by adding ActiveSupport dependency
|
79
|
+
- Fixed method visibility issues with `validate_messages` method
|
80
|
+
|
81
|
+
### Changed
|
82
|
+
- Updated gemspec to exclude generated files and security reports
|
83
|
+
- Added `activesupport` dependency for numeric extensions
|
84
|
+
- Improved error handling and method accessibility
|
85
|
+
|
86
|
+
## [0.1.8] - 2024-09-21
|
87
|
+
|
88
|
+
### Fixed
|
89
|
+
- Fixed `NoMethodError: undefined method 'validate_messages'` by making method public
|
90
|
+
- Resolved method visibility conflicts in security module
|
91
|
+
- Fixed file loading order issues
|
92
|
+
|
93
|
+
### Changed
|
94
|
+
- Updated security module to properly load input validator
|
95
|
+
- Improved method accessibility and error handling
|
96
|
+
|
97
|
+
## [0.1.7] - 2024-09-21
|
98
|
+
|
99
|
+
### Fixed
|
100
|
+
- Fixed `NoMethodError: undefined method 'validate_messages'` in chat functionality
|
101
|
+
- Resolved method visibility issues in security module
|
102
|
+
- Fixed file loading conflicts between duplicate classes
|
103
|
+
|
104
|
+
### Changed
|
105
|
+
- Updated security module to use proper file loading
|
106
|
+
- Improved error handling and method accessibility
|
107
|
+
|
108
|
+
## [0.1.6] - 2024-09-21
|
109
|
+
|
110
|
+
### Fixed
|
111
|
+
- Fixed `NoMethodError: undefined method 'validate_messages'` by updating security module
|
112
|
+
- Resolved method visibility issues
|
113
|
+
- Fixed file loading conflicts
|
114
|
+
|
115
|
+
### Changed
|
116
|
+
- Updated security module to properly load input validator
|
117
|
+
- Improved method accessibility
|
118
|
+
|
119
|
+
## [0.1.5] - 2024-09-21
|
120
|
+
|
121
|
+
### Fixed
|
122
|
+
- Fixed `NoMethodError: undefined method 'validate_messages'` by updating security module
|
123
|
+
- Resolved method visibility conflicts
|
124
|
+
- Fixed file loading order issues
|
125
|
+
|
126
|
+
### Changed
|
127
|
+
- Updated security module to use proper file loading
|
128
|
+
- Improved method accessibility
|
129
|
+
|
130
|
+
## [0.1.4] - 2024-09-21
|
131
|
+
|
132
|
+
### Fixed
|
133
|
+
- Fixed `NoMethodError: undefined method 'validate_messages'` by making method public
|
134
|
+
- Resolved method visibility issues in security module
|
135
|
+
- Fixed file loading conflicts
|
136
|
+
|
137
|
+
### Changed
|
138
|
+
- Updated security module to properly load input validator
|
139
|
+
- Improved method accessibility
|
140
|
+
|
141
|
+
## [0.1.3] - 2024-09-21
|
142
|
+
|
143
|
+
### Fixed
|
144
|
+
- Fixed `NoMethodError: undefined method 'validate_messages'` by making method public
|
145
|
+
- Resolved method visibility issues in security module
|
146
|
+
- Fixed file loading conflicts
|
147
|
+
|
148
|
+
### Changed
|
149
|
+
- Updated security module to properly load input validator
|
150
|
+
- Improved method accessibility
|
151
|
+
|
152
|
+
## [0.1.2] - 2024-09-21
|
153
|
+
|
154
|
+
### Fixed
|
155
|
+
- Fixed CI validation errors by excluding `.gem` files from gemspec
|
156
|
+
- Resolved `NoMethodError: undefined method 'megabytes'` by adding ActiveSupport dependency
|
157
|
+
- Fixed method visibility issues
|
158
|
+
|
159
|
+
### Changed
|
160
|
+
- Updated gemspec to exclude generated files
|
161
|
+
- Added `activesupport` dependency for numeric extensions
|
162
|
+
- Improved error handling
|
163
|
+
|
164
|
+
## [0.1.1] - 2024-09-21
|
165
|
+
|
166
|
+
### Fixed
|
167
|
+
- Fixed `NoMethodError: undefined method 'megabytes'` by adding ActiveSupport dependency
|
168
|
+
- Resolved method visibility issues in security module
|
169
|
+
- Fixed file loading conflicts
|
170
|
+
|
171
|
+
### Changed
|
172
|
+
- Added `activesupport` dependency for numeric extensions
|
173
|
+
- Updated security module to properly load input validator
|
174
|
+
- Improved method accessibility
|
175
|
+
|
176
|
+
## [0.1.0] - 2024-09-21
|
177
|
+
|
178
|
+
### Added
|
179
|
+
- Initial release of Rails AI gem
|
180
|
+
- Multi-provider support for OpenAI, Anthropic (Claude), and Google Gemini
|
181
|
+
- Direct API integration without external gem dependencies
|
182
|
+
- Full multimodal capabilities (text, image, video, audio, embeddings)
|
183
|
+
- Context awareness with UserContext, WindowContext, and ImageContext
|
184
|
+
- Performance optimizations with caching, connection pooling, and batch processing
|
185
|
+
- Agent AI system with BaseAgent, specialized agents, and team collaboration
|
186
|
+
- Memory system with importance-based retention and search
|
187
|
+
- Message bus for inter-agent communication
|
188
|
+
- Task queue with priority-based management and deduplication
|
189
|
+
- Specialized agents: ResearchAgent, CreativeAgent, TechnicalAgent, CoordinatorAgent
|
190
|
+
- Agent teams with various collaboration strategies
|
191
|
+
- Agent Manager for centralized system management
|
192
|
+
- Comprehensive security framework
|
193
|
+
- Input validation and sanitization
|
194
|
+
- Rate limiting and content filtering
|
195
|
+
- Secure file handling and API security
|
196
|
+
- SSRF protection and API key management
|
197
|
+
- Audit logging and error handling
|
198
|
+
- Custom security scanner
|
199
|
+
- CI/CD security monitoring
|
200
|
+
- Legal protection framework for Canadian jurisdiction
|
201
|
+
- Commercial license template and monitoring system
|
202
|
+
- Comprehensive documentation and wiki
|
203
|
+
- Rails 5.2+ compatibility with Ruby 3+ support
|
204
|
+
- MIT License with non-commercial use restrictions
|
205
|
+
|
206
|
+
### Features
|
207
|
+
- **Text Generation**: Support for GPT-4o, GPT-4, GPT-3.5-turbo, Claude, and Gemini models
|
208
|
+
- **Image Generation**: DALL-E 3, DALL-E 2, and Gemini image generation
|
209
|
+
- **Image Analysis**: Vision models for image understanding and analysis
|
210
|
+
- **Video Generation**: Video creation and editing capabilities
|
211
|
+
- **Audio Processing**: Speech generation and audio transcription
|
212
|
+
- **Embeddings**: Vector embeddings for semantic search and similarity
|
213
|
+
- **Streaming**: Real-time streaming responses for better user experience
|
214
|
+
- **Caching**: Intelligent caching system for improved performance
|
215
|
+
- **Context Awareness**: User, window, and image context integration
|
216
|
+
- **Agent System**: Autonomous AI agents with collaboration capabilities
|
217
|
+
- **Security**: Comprehensive security framework with multiple protection layers
|
218
|
+
- **Performance**: Optimized for speed with connection pooling and batch processing
|
219
|
+
- **Monitoring**: Continuous monitoring for security and unauthorized use
|
220
|
+
- **Legal Protection**: Canadian legal framework with commercial licensing
|
221
|
+
|
222
|
+
### Technical Details
|
223
|
+
- **Rails Compatibility**: Rails 5.2, 6.x, 7.x, 8.x
|
224
|
+
- **Ruby Compatibility**: Ruby 3.0+
|
225
|
+
- **Dependencies**: Minimal external dependencies for maximum compatibility
|
226
|
+
- **Performance**: Optimized for speed with caching and connection pooling
|
227
|
+
- **Security**: Multiple security layers with input validation and sanitization
|
228
|
+
- **Monitoring**: Continuous monitoring with CI/CD integration
|
229
|
+
- **Documentation**: Comprehensive documentation and wiki
|
230
|
+
- **Legal**: Non-commercial license with commercial licensing available
|
231
|
+
|
232
|
+
### Breaking Changes
|
233
|
+
- None in initial release
|
234
|
+
|
235
|
+
### Deprecated
|
236
|
+
- None in initial release
|
237
|
+
|
238
|
+
### Removed
|
239
|
+
- None in initial release
|
240
|
+
|
241
|
+
### Security
|
242
|
+
- Comprehensive security framework implemented
|
243
|
+
- Input validation and sanitization
|
244
|
+
- Rate limiting and content filtering
|
245
|
+
- Secure file handling and API security
|
246
|
+
- SSRF protection and API key management
|
247
|
+
- Audit logging and error handling
|
248
|
+
- Custom security scanner
|
249
|
+
- CI/CD security monitoring
|
250
|
+
|
251
|
+
### Performance
|
252
|
+
- Intelligent caching system
|
253
|
+
- Connection pooling for HTTP requests
|
254
|
+
- Batch processing capabilities
|
255
|
+
- Lazy loading for improved performance
|
256
|
+
- Performance monitoring and optimization
|
257
|
+
- Memory management and optimization
|
258
|
+
|
259
|
+
### Documentation
|
260
|
+
- Comprehensive README with usage examples
|
261
|
+
- Complete API documentation
|
262
|
+
- Installation and setup guides
|
263
|
+
- Contributing guidelines
|
264
|
+
- Security documentation
|
265
|
+
- Legal protection guide
|
266
|
+
- Commercial license template
|
267
|
+
- GitHub wiki with detailed documentation
|
268
|
+
|
269
|
+
### Legal
|
270
|
+
- MIT License with non-commercial use restrictions
|
271
|
+
- Commercial licensing available for $999/year
|
272
|
+
- Canadian legal framework
|
273
|
+
- Copyright protection and monitoring
|
274
|
+
- Cease and desist templates
|
275
|
+
- Legal protection guide
|
276
|
+
|
277
|
+
---
|
278
|
+
|
279
|
+
## Version History Summary
|
280
|
+
|
281
|
+
- **0.2.3**: Fixed agent team creation and improved task execution
|
282
|
+
- **0.2.2**: Fixed streaming demo and cookie overflow issues
|
283
|
+
- **0.2.1**: Added web search integration and real-time information
|
284
|
+
- **0.2.0**: Added comprehensive security framework
|
285
|
+
- **0.1.9**: Fixed CI validation and ActiveSupport dependencies
|
286
|
+
- **0.1.8**: Fixed method visibility and file loading issues
|
287
|
+
- **0.1.7**: Fixed validate_messages method accessibility
|
288
|
+
- **0.1.6**: Updated security module and method accessibility
|
289
|
+
- **0.1.5**: Fixed method visibility and file loading conflicts
|
290
|
+
- **0.1.4**: Made validate_messages method public
|
291
|
+
- **0.1.3**: Fixed method visibility issues
|
292
|
+
- **0.1.2**: Fixed CI validation and added ActiveSupport dependency
|
293
|
+
- **0.1.1**: Fixed megabytes method and added ActiveSupport dependency
|
294
|
+
- **0.1.0**: Initial release with comprehensive AI capabilities
|
295
|
+
|
296
|
+
## Contributing
|
297
|
+
|
298
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
|
299
|
+
|
300
|
+
## License
|
301
|
+
|
302
|
+
This project is licensed under the MIT License with Non-Commercial Use Restrictions - see the [LICENSE](LICENSE) file for details.
|
303
|
+
|
304
|
+
## Support
|
305
|
+
|
306
|
+
For support, please open an issue on GitHub or contact the maintainer at amahdanieljack@gmail.com.
|
307
|
+
|
308
|
+
## Commercial Licensing
|
309
|
+
|
310
|
+
For commercial use, please contact amahdanieljack@gmail.com for licensing information. Commercial license fee: $999/year.
|
data/lib/rails_ai/version.rb
CHANGED
data/lib/rails_ai.rb
CHANGED
@@ -48,169 +48,58 @@ module RailsAi
|
|
48
48
|
class << self
|
49
49
|
# Version compatibility helpers
|
50
50
|
def rails_version
|
51
|
-
Rails.version.
|
51
|
+
Rails.version.to_f
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
55
|
-
|
54
|
+
def ruby_version
|
55
|
+
RUBY_VERSION.to_f
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
58
|
+
# Configuration
|
59
|
+
def config
|
60
|
+
@config ||= Config.new
|
60
61
|
end
|
61
62
|
|
62
|
-
def
|
63
|
-
|
63
|
+
def configure
|
64
|
+
yield(config)
|
64
65
|
end
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
case config.provider.to_sym
|
74
|
-
when :openai then Providers::SecureOpenAIAdapter.new
|
75
|
-
when :anthropic then Providers::SecureAnthropicAdapter.new
|
76
|
-
when :gemini then Providers::GeminiAdapter.new
|
77
|
-
when :dummy then Providers::DummyAdapter.new
|
78
|
-
else Providers::DummyAdapter.new
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Agent management
|
84
|
-
def agent_manager
|
85
|
-
@agent_manager ||= Agents::AgentManager.new
|
86
|
-
end
|
87
|
-
|
88
|
-
def create_agent(name:, role:, capabilities: [], **opts)
|
89
|
-
agent = Agents::BaseAgent.new(
|
90
|
-
name: name,
|
91
|
-
role: role,
|
92
|
-
capabilities: capabilities,
|
93
|
-
**opts
|
67
|
+
# Performance optimizations
|
68
|
+
def connection_pool
|
69
|
+
@connection_pool ||= Concurrent::ThreadPoolExecutor.new(
|
70
|
+
min_threads: 2,
|
71
|
+
max_threads: 10,
|
72
|
+
max_queue: 100,
|
73
|
+
auto_terminate: true
|
94
74
|
)
|
95
|
-
agent_manager.register_agent(agent)
|
96
|
-
agent
|
97
|
-
end
|
98
|
-
|
99
|
-
def create_research_agent(name: "ResearchAgent", **opts)
|
100
|
-
agent = Agents::ResearchAgent.new(name: name, **opts)
|
101
|
-
agent_manager.register_agent(agent)
|
102
|
-
agent
|
103
|
-
end
|
104
|
-
|
105
|
-
def create_creative_agent(name: "CreativeAgent", **opts)
|
106
|
-
agent = Agents::CreativeAgent.new(name: name, **opts)
|
107
|
-
agent_manager.register_agent(agent)
|
108
|
-
agent
|
109
|
-
end
|
110
|
-
|
111
|
-
def create_technical_agent(name: "TechnicalAgent", **opts)
|
112
|
-
agent = Agents::TechnicalAgent.new(name: name, **opts)
|
113
|
-
agent_manager.register_agent(agent)
|
114
|
-
agent
|
115
|
-
end
|
116
|
-
|
117
|
-
def create_coordinator_agent(name: "CoordinatorAgent", **opts)
|
118
|
-
agent = Agents::CoordinatorAgent.new(name: name, **opts)
|
119
|
-
agent_manager.register_agent(agent)
|
120
|
-
agent
|
121
|
-
end
|
122
|
-
|
123
|
-
def get_agent(name)
|
124
|
-
agent_manager.get_agent(name)
|
125
|
-
end
|
126
|
-
|
127
|
-
def list_agents
|
128
|
-
agent_manager.list_agents
|
129
|
-
end
|
130
|
-
|
131
|
-
def start_agents!
|
132
|
-
agent_manager.start!
|
133
|
-
end
|
134
|
-
|
135
|
-
def stop_agents!
|
136
|
-
agent_manager.stop!
|
137
|
-
end
|
138
|
-
|
139
|
-
# Task management
|
140
|
-
def submit_task(task)
|
141
|
-
agent_manager.submit_task(task)
|
142
|
-
end
|
143
|
-
|
144
|
-
def assign_task(task, agent_name)
|
145
|
-
agent_manager.assign_task_to_agent(task, agent_name)
|
146
|
-
end
|
147
|
-
|
148
|
-
def auto_assign_task(task)
|
149
|
-
agent_manager.auto_assign_task(task)
|
150
|
-
end
|
151
|
-
|
152
|
-
# Agent teams
|
153
|
-
def create_agent_team(name, agents, strategy: :round_robin)
|
154
|
-
agent_manager.create_agent_team(name, agents, collaboration_strategy: strategy)
|
155
|
-
end
|
156
|
-
|
157
|
-
def orchestrate_collaboration(task, agent_names)
|
158
|
-
agent_manager.orchestrate_collaboration(task, agent_names)
|
159
|
-
end
|
160
|
-
|
161
|
-
# Agent communication
|
162
|
-
def send_agent_message(from_agent, to_agent, message)
|
163
|
-
agent_manager.send_message(from_agent, to_agent, message)
|
164
75
|
end
|
165
76
|
|
166
|
-
def
|
167
|
-
|
77
|
+
def batch_processor
|
78
|
+
@batch_processor ||= Concurrent::ThreadPoolExecutor.new(
|
79
|
+
min_threads: 1,
|
80
|
+
max_threads: 5,
|
81
|
+
max_queue: 50,
|
82
|
+
auto_terminate: true
|
83
|
+
)
|
168
84
|
end
|
169
85
|
|
170
|
-
|
171
|
-
|
172
|
-
agent_manager.system_status
|
86
|
+
def smart_cache
|
87
|
+
@smart_cache ||= Cache.new
|
173
88
|
end
|
174
89
|
|
175
|
-
def
|
176
|
-
|
90
|
+
def request_deduplicator
|
91
|
+
@request_deduplicator ||= RequestDeduplicator.new
|
177
92
|
end
|
178
93
|
|
179
|
-
# Performance monitoring
|
180
94
|
def performance_monitor
|
181
|
-
@performance_monitor ||= Performance::
|
182
|
-
end
|
183
|
-
|
184
|
-
def metrics
|
185
|
-
performance_monitor.metrics
|
186
|
-
end
|
187
|
-
|
188
|
-
# Connection pool for HTTP requests
|
189
|
-
def connection_pool
|
190
|
-
@connection_pool ||= Performance::ConnectionPool.new(size: config.connection_pool_size)
|
95
|
+
@performance_monitor ||= Performance::Monitor.new
|
191
96
|
end
|
192
97
|
|
193
|
-
|
194
|
-
|
195
|
-
@smart_cache ||= Performance::SmartCache.new(
|
196
|
-
compression_threshold: config.compression_threshold
|
197
|
-
)
|
198
|
-
end
|
199
|
-
|
200
|
-
# Request deduplication
|
201
|
-
def request_deduplicator
|
202
|
-
@request_deduplicator ||= Performance::RequestDeduplicator.new
|
203
|
-
end
|
204
|
-
|
205
|
-
# Batch processor for multiple operations
|
206
|
-
def batch_processor
|
207
|
-
@batch_processor ||= Performance::BatchProcessor.new(
|
208
|
-
batch_size: config.batch_size,
|
209
|
-
flush_interval: config.flush_interval
|
210
|
-
)
|
98
|
+
def agent_manager
|
99
|
+
@agent_manager ||= Agents::AgentManager.new
|
211
100
|
end
|
212
101
|
|
213
|
-
#
|
102
|
+
# Core AI methods
|
214
103
|
def chat(prompt_or_messages, model: config.default_model, **opts)
|
215
104
|
performance_monitor.measure(:chat) do
|
216
105
|
messages = normalize_messages(prompt_or_messages)
|
@@ -235,302 +124,220 @@ module RailsAi
|
|
235
124
|
end
|
236
125
|
end
|
237
126
|
|
238
|
-
def embed(texts, model:
|
127
|
+
def embed(texts, model: "text-embedding-3-small", **opts)
|
239
128
|
performance_monitor.measure(:embed) do
|
240
|
-
|
241
|
-
cache_key = [:embed, model,
|
129
|
+
texts_array = Array(texts)
|
130
|
+
cache_key = [:embed, model, texts_array.hash]
|
242
131
|
|
243
132
|
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
244
133
|
request_deduplicator.deduplicate(cache_key) do
|
245
|
-
provider.embed!(texts:
|
134
|
+
provider.embed!(texts: texts_array, model: model, **opts)
|
246
135
|
end
|
247
136
|
end
|
248
137
|
end
|
249
138
|
end
|
250
139
|
|
251
|
-
#
|
252
|
-
def
|
253
|
-
performance_monitor.measure(:
|
254
|
-
|
255
|
-
|
256
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
257
|
-
request_deduplicator.deduplicate(cache_key) do
|
258
|
-
provider.generate_image!(prompt: prompt, model: model, size: size, quality: quality, **opts)
|
259
|
-
end
|
260
|
-
end
|
140
|
+
# Multimodal capabilities
|
141
|
+
def analyze_image(image, prompt, model: "gpt-4o", **opts)
|
142
|
+
performance_monitor.measure(:analyze_image) do
|
143
|
+
provider.analyze_image!(image: image, prompt: prompt, model: model, **opts)
|
261
144
|
end
|
262
145
|
end
|
263
146
|
|
264
|
-
def
|
265
|
-
performance_monitor.measure(:
|
266
|
-
|
267
|
-
|
268
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
269
|
-
request_deduplicator.deduplicate(cache_key) do
|
270
|
-
provider.edit_image!(image: image, prompt: prompt, mask: mask, size: size, **opts)
|
271
|
-
end
|
272
|
-
end
|
147
|
+
def generate_image(prompt, model: "dall-e-3", **opts)
|
148
|
+
performance_monitor.measure(:generate_image) do
|
149
|
+
provider.generate_image!(prompt: prompt, model: model, **opts)
|
273
150
|
end
|
274
151
|
end
|
275
152
|
|
276
|
-
def
|
277
|
-
performance_monitor.measure(:
|
278
|
-
|
279
|
-
|
280
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
281
|
-
request_deduplicator.deduplicate(cache_key) do
|
282
|
-
provider.create_variation!(image: image, size: size, **opts)
|
283
|
-
end
|
284
|
-
end
|
153
|
+
def analyze_video(video, prompt, model: "gpt-4o", **opts)
|
154
|
+
performance_monitor.measure(:analyze_video) do
|
155
|
+
provider.analyze_video!(video: video, prompt: prompt, model: model, **opts)
|
285
156
|
end
|
286
157
|
end
|
287
158
|
|
288
|
-
|
289
|
-
def generate_video(prompt, model: "sora", duration: 5, **opts)
|
159
|
+
def generate_video(prompt, model: "runway-gen-3", **opts)
|
290
160
|
performance_monitor.measure(:generate_video) do
|
291
|
-
|
292
|
-
|
293
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
294
|
-
request_deduplicator.deduplicate(cache_key) do
|
295
|
-
provider.generate_video!(prompt: prompt, model: model, duration: duration, **opts)
|
296
|
-
end
|
297
|
-
end
|
161
|
+
provider.generate_video!(prompt: prompt, model: model, **opts)
|
298
162
|
end
|
299
163
|
end
|
300
164
|
|
301
|
-
def
|
302
|
-
performance_monitor.measure(:
|
303
|
-
|
304
|
-
|
305
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
306
|
-
request_deduplicator.deduplicate(cache_key) do
|
307
|
-
provider.edit_video!(video: video, prompt: prompt, **opts)
|
308
|
-
end
|
309
|
-
end
|
165
|
+
def analyze_audio(audio, prompt, model: "whisper-1", **opts)
|
166
|
+
performance_monitor.measure(:analyze_audio) do
|
167
|
+
provider.analyze_audio!(audio: audio, prompt: prompt, model: model, **opts)
|
310
168
|
end
|
311
169
|
end
|
312
170
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
cache_key = [:speech, model, text.hash, voice]
|
317
|
-
|
318
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
319
|
-
request_deduplicator.deduplicate(cache_key) do
|
320
|
-
provider.generate_speech!(text: text, model: model, voice: voice, **opts)
|
321
|
-
end
|
322
|
-
end
|
171
|
+
def generate_audio(prompt, model: "tts-1", **opts)
|
172
|
+
performance_monitor.measure(:generate_audio) do
|
173
|
+
provider.generate_audio!(prompt: prompt, model: model, **opts)
|
323
174
|
end
|
324
175
|
end
|
325
176
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
provider.transcribe_audio!(audio: audio, model: model, **opts)
|
333
|
-
end
|
334
|
-
end
|
177
|
+
# Context awareness
|
178
|
+
def chat_with_context(prompt, context_objects = [], model: config.default_model, **opts)
|
179
|
+
performance_monitor.measure(:chat_with_context) do
|
180
|
+
context_analyzer = ContextAnalyzer.new
|
181
|
+
enhanced_prompt = context_analyzer.enhance_prompt(prompt, context_objects)
|
182
|
+
chat(enhanced_prompt, model: model, **opts)
|
335
183
|
end
|
336
184
|
end
|
337
185
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
344
|
-
request_deduplicator.deduplicate(cache_key) do
|
345
|
-
provider.analyze_image!(image: image, prompt: prompt, model: model, **opts)
|
346
|
-
end
|
347
|
-
end
|
186
|
+
def analyze_window_context(url, referrer, user_agent, **opts)
|
187
|
+
performance_monitor.measure(:analyze_window_context) do
|
188
|
+
window_context = WindowContext.new(url: url, referrer: referrer, user_agent: user_agent)
|
189
|
+
window_context.analyze(**opts)
|
348
190
|
end
|
349
191
|
end
|
350
192
|
|
351
|
-
def
|
352
|
-
performance_monitor.measure(:
|
353
|
-
|
354
|
-
|
355
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
356
|
-
request_deduplicator.deduplicate(cache_key) do
|
357
|
-
provider.analyze_video!(video: video, prompt: prompt, model: model, **opts)
|
358
|
-
end
|
359
|
-
end
|
193
|
+
def analyze_image_context(image, **opts)
|
194
|
+
performance_monitor.measure(:analyze_image_context) do
|
195
|
+
image_context = ImageContext.new(image)
|
196
|
+
image_context.analyze(**opts)
|
360
197
|
end
|
361
198
|
end
|
362
199
|
|
363
|
-
#
|
364
|
-
def
|
365
|
-
|
366
|
-
requests.map do |request|
|
367
|
-
batch_processor.add_operation(-> { chat(request[:prompt], **request.except(:prompt)) })
|
368
|
-
end
|
369
|
-
end
|
200
|
+
# Agent system
|
201
|
+
def create_agent(name, type: :general, **opts)
|
202
|
+
agent_manager.create_agent(name, type: type, **opts)
|
370
203
|
end
|
371
204
|
|
372
|
-
def
|
373
|
-
|
374
|
-
texts_array.map do |texts|
|
375
|
-
batch_processor.add_operation(-> { embed(texts) })
|
376
|
-
end
|
377
|
-
end
|
205
|
+
def create_research_agent(name: "Research Agent", **opts)
|
206
|
+
agent_manager.create_agent(name, type: :research, **opts)
|
378
207
|
end
|
379
208
|
|
380
|
-
|
381
|
-
|
382
|
-
performance_monitor.measure(:analyze_image_with_context) do
|
383
|
-
cache_key = [:context_image_analysis, prompt.hash, image.hash, user_context.hash, window_context.hash, image_context.hash]
|
384
|
-
|
385
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
386
|
-
analyzer = ContextAnalyzer.new(
|
387
|
-
user_context: user_context,
|
388
|
-
window_context: window_context,
|
389
|
-
image_context: image_context
|
390
|
-
)
|
391
|
-
analyzer.analyze_with_context(image, prompt, **opts)
|
392
|
-
end
|
393
|
-
end
|
209
|
+
def create_creative_agent(name: "Creative Agent", **opts)
|
210
|
+
agent_manager.create_agent(name, type: :creative, **opts)
|
394
211
|
end
|
395
212
|
|
396
|
-
def
|
397
|
-
|
398
|
-
cache_key = [:context_generate, prompt.hash, user_context.hash, window_context.hash]
|
399
|
-
|
400
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
401
|
-
analyzer = ContextAnalyzer.new(
|
402
|
-
user_context: user_context,
|
403
|
-
window_context: window_context
|
404
|
-
)
|
405
|
-
analyzer.generate_with_context(prompt, **opts)
|
406
|
-
end
|
407
|
-
end
|
213
|
+
def create_technical_agent(name: "Technical Agent", **opts)
|
214
|
+
agent_manager.create_agent(name, type: :technical, **opts)
|
408
215
|
end
|
409
216
|
|
410
|
-
def
|
411
|
-
|
412
|
-
cache_key = [:context_image_generate, prompt.hash, user_context.hash, window_context.hash]
|
413
|
-
|
414
|
-
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
415
|
-
analyzer = ContextAnalyzer.new(
|
416
|
-
user_context: user_context,
|
417
|
-
window_context: window_context
|
418
|
-
)
|
419
|
-
analyzer.generate_image_with_context(prompt, **opts)
|
420
|
-
end
|
421
|
-
end
|
217
|
+
def create_agent_team(name, agents, strategy: :round_robin, **opts)
|
218
|
+
agent_manager.create_agent_team(name, agents, collaboration_strategy: strategy, **opts)
|
422
219
|
end
|
423
220
|
|
424
|
-
|
425
|
-
|
426
|
-
|
221
|
+
def submit_task(task, agent_team = nil)
|
222
|
+
if agent_team
|
223
|
+
agent_team.assign_task(task)
|
224
|
+
else
|
225
|
+
agent_manager.submit_task(task)
|
226
|
+
end
|
427
227
|
end
|
428
228
|
|
429
|
-
|
430
|
-
|
229
|
+
# Provider management
|
230
|
+
def provider
|
231
|
+
case config.provider.to_sym
|
232
|
+
when :openai then Providers::SecureOpenAIAdapter.new
|
233
|
+
when :anthropic then Providers::SecureAnthropicAdapter.new
|
234
|
+
when :gemini then Providers::GeminiAdapter.new
|
235
|
+
when :dummy then Providers::DummyAdapter.new
|
236
|
+
else Providers::DummyAdapter.new
|
237
|
+
end
|
431
238
|
end
|
432
239
|
|
433
|
-
def
|
434
|
-
|
240
|
+
def provider=(new_provider)
|
241
|
+
config.provider = new_provider
|
435
242
|
end
|
436
243
|
|
437
|
-
|
438
|
-
|
244
|
+
# Utility methods
|
245
|
+
def normalize_messages(prompt_or_messages)
|
246
|
+
if prompt_or_messages.is_a?(String)
|
247
|
+
[{ role: "user", content: prompt_or_messages }]
|
248
|
+
else
|
249
|
+
prompt_or_messages
|
250
|
+
end
|
439
251
|
end
|
440
252
|
|
441
|
-
def
|
442
|
-
|
253
|
+
def redact_sensitive_data(text)
|
254
|
+
Redactor.call(text)
|
443
255
|
end
|
444
256
|
|
445
|
-
def
|
446
|
-
|
257
|
+
def log_event(kind:, name:, payload: {}, latency_ms: nil)
|
258
|
+
Events.log!(kind: kind, name: name, payload: payload, latency_ms: latency_ms)
|
447
259
|
end
|
448
260
|
|
449
|
-
#
|
450
|
-
def
|
451
|
-
|
452
|
-
provider
|
453
|
-
connection_pool
|
454
|
-
smart_cache
|
455
|
-
request_deduplicator
|
456
|
-
batch_processor
|
457
|
-
agent_manager
|
261
|
+
# Security methods
|
262
|
+
def validate_input(input, type: :text)
|
263
|
+
Security::InputValidator.validate(input, type: type)
|
458
264
|
end
|
459
265
|
|
460
|
-
def
|
461
|
-
|
266
|
+
def sanitize_content(content)
|
267
|
+
Security::ContentSanitizer.sanitize(content)
|
462
268
|
end
|
463
269
|
|
464
|
-
def
|
465
|
-
|
270
|
+
def check_rate_limit(identifier, limit: 100, window: 1.hour)
|
271
|
+
Security::RateLimiter.check(identifier, limit: limit, window: window)
|
466
272
|
end
|
467
273
|
|
468
|
-
|
469
|
-
|
470
|
-
def normalize_messages(prompt_or_messages)
|
471
|
-
messages = prompt_or_messages.is_a?(Array) ? prompt_or_messages : [{role: "user", content: prompt_or_messages}]
|
472
|
-
text = RailsAi::Redactor.call(messages.last[:content])
|
473
|
-
messages[-1] = messages.last.merge(content: text)
|
474
|
-
messages
|
274
|
+
def scan_for_vulnerabilities
|
275
|
+
Security::VulnerabilityScanner.scan
|
475
276
|
end
|
476
|
-
end
|
477
277
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
end
|
278
|
+
def handle_security_error(error, context = {})
|
279
|
+
Security::ErrorHandler.handle_security_error(error, context)
|
280
|
+
end
|
482
281
|
|
483
|
-
|
484
|
-
|
485
|
-
|
282
|
+
# Response cleaning utility
|
283
|
+
def clean_response(raw_response)
|
284
|
+
return nil if raw_response.nil?
|
486
285
|
|
487
|
-
|
488
|
-
|
489
|
-
|
286
|
+
# Convert to string
|
287
|
+
response = raw_response.to_s
|
288
|
+
|
289
|
+
# Ensure UTF-8 encoding
|
290
|
+
response = response.encode('UTF-8', 'UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
291
|
+
|
292
|
+
# Remove any control characters that might cause issues
|
293
|
+
response = response.gsub(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/, '')
|
294
|
+
|
295
|
+
response
|
296
|
+
end
|
490
297
|
|
491
|
-
|
492
|
-
|
493
|
-
|
298
|
+
# Enhanced chat method with automatic response cleaning
|
299
|
+
def chat_clean(prompt_or_messages, model: config.default_model, **opts)
|
300
|
+
raw_response = chat(prompt_or_messages, model: model, **opts)
|
301
|
+
clean_response(raw_response)
|
302
|
+
end
|
494
303
|
|
495
|
-
|
496
|
-
|
304
|
+
# Enhanced web search chat with automatic response cleaning
|
305
|
+
def chat_with_web_search_clean(prompt, model: config.default_model, **opts)
|
306
|
+
raw_response = chat_with_web_search(prompt, model: model, **opts)
|
307
|
+
clean_response(raw_response)
|
308
|
+
end
|
497
309
|
end
|
310
|
+
end
|
498
311
|
|
499
|
-
def self.handle_security_error(error, context = {})
|
500
|
-
Security::ErrorHandler.handle_security_error(error, context)
|
501
|
-
end
|
502
312
|
require_relative "rails_ai/web_search"
|
503
313
|
|
504
|
-
|
505
|
-
|
506
|
-
#
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
web_context
|
519
|
-
search_results.each_with_index do |result, index|
|
520
|
-
web_context += "#{index + 1}. #{result[:title]}\n #{result[:snippet]}\n Source: #{result[:link]}\n\n"
|
521
|
-
end
|
522
|
-
|
523
|
-
enhanced_prompt = "#{prompt}\n\nPlease use the following web search results to provide current, up-to-date information:#{web_context}"
|
524
|
-
|
525
|
-
# Get AI response with web context
|
526
|
-
chat(enhanced_prompt, model: model, **opts)
|
527
|
-
rescue WebSearch::SearchError => e
|
528
|
-
# Fallback to regular chat if web search fails
|
529
|
-
chat(prompt, model: model, **opts)
|
314
|
+
# Web-enhanced chat with real-time information
|
315
|
+
def RailsAi.chat_with_web_search(prompt, model: RailsAi.config.default_model, **opts)
|
316
|
+
# Check if the prompt needs web search
|
317
|
+
web_keywords = ['current', 'latest', 'today', 'now', 'recent', 'weather', 'news', 'stock', 'price']
|
318
|
+
needs_web_search = web_keywords.any? { |keyword| prompt.downcase.include?(keyword) }
|
319
|
+
|
320
|
+
if needs_web_search
|
321
|
+
begin
|
322
|
+
# Perform web search
|
323
|
+
search_results = WebSearch.search(prompt, num_results: 3)
|
324
|
+
|
325
|
+
# Enhance the prompt with web results
|
326
|
+
web_context = "\n\nRecent web search results:\n"
|
327
|
+
search_results.each_with_index do |result, index|
|
328
|
+
web_context += "#{index + 1}. #{result[:title]}\n #{result[:snippet]}\n Source: #{result[:link]}\n\n"
|
530
329
|
end
|
531
|
-
|
532
|
-
#
|
533
|
-
|
534
|
-
|
330
|
+
|
331
|
+
enhanced_prompt = "#{prompt}\n\nPlease use the following web search results to provide current, up-to-date information:#{web_context}"
|
332
|
+
|
333
|
+
# Get AI response with web context
|
334
|
+
RailsAi.chat(enhanced_prompt, model: model, **opts)
|
335
|
+
rescue WebSearch::SearchError => e
|
336
|
+
# Fallback to regular chat if web search fails
|
337
|
+
RailsAi.chat(prompt, model: model, **opts)
|
338
|
+
end
|
339
|
+
else
|
340
|
+
# Regular chat for non-time-sensitive queries
|
341
|
+
RailsAi.chat(prompt, model: model, **opts)
|
535
342
|
end
|
536
343
|
end
|
data/setup_wiki.sh
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Setup GitHub Wiki for Rails AI Gem
|
4
|
+
echo "Setting up GitHub Wiki for Rails AI Gem..."
|
5
|
+
|
6
|
+
# Check if we're in the right directory
|
7
|
+
if [ ! -d "wiki" ]; then
|
8
|
+
echo "Error: wiki directory not found. Please run this script from the rails_ai root directory."
|
9
|
+
exit 1
|
10
|
+
fi
|
11
|
+
|
12
|
+
# Clone the wiki repository
|
13
|
+
echo "Cloning wiki repository..."
|
14
|
+
git clone https://github.com/DanielAmah/rails_ai.wiki.git wiki_repo
|
15
|
+
|
16
|
+
if [ $? -ne 0 ]; then
|
17
|
+
echo "Error: Could not clone wiki repository. Make sure the wiki is enabled on GitHub."
|
18
|
+
echo "To enable wiki:"
|
19
|
+
echo "1. Go to https://github.com/DanielAmah/rails_ai"
|
20
|
+
echo "2. Click on 'Settings' tab"
|
21
|
+
echo "3. Scroll down to 'Features' section"
|
22
|
+
echo "4. Check 'Wikis' to enable it"
|
23
|
+
echo "5. Run this script again"
|
24
|
+
exit 1
|
25
|
+
fi
|
26
|
+
|
27
|
+
# Copy wiki files
|
28
|
+
echo "Copying wiki files..."
|
29
|
+
cp wiki/*.md wiki_repo/
|
30
|
+
|
31
|
+
# Navigate to wiki repo
|
32
|
+
cd wiki_repo
|
33
|
+
|
34
|
+
# Add and commit files
|
35
|
+
echo "Adding wiki files to git..."
|
36
|
+
git add .
|
37
|
+
git commit -m "Add comprehensive wiki documentation for Rails AI Gem"
|
38
|
+
|
39
|
+
# Push to GitHub
|
40
|
+
echo "Pushing wiki to GitHub..."
|
41
|
+
git push origin master
|
42
|
+
|
43
|
+
if [ $? -eq 0 ]; then
|
44
|
+
echo "✅ Wiki successfully set up!"
|
45
|
+
echo "You can now view it at: https://github.com/DanielAmah/rails_ai/wiki"
|
46
|
+
else
|
47
|
+
echo "❌ Error pushing wiki to GitHub"
|
48
|
+
exit 1
|
49
|
+
fi
|
50
|
+
|
51
|
+
# Clean up
|
52
|
+
cd ..
|
53
|
+
rm -rf wiki_repo
|
54
|
+
|
55
|
+
echo "Wiki setup complete!"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_ai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Amah
|
@@ -279,6 +279,7 @@ files:
|
|
279
279
|
- ".rspec_status"
|
280
280
|
- AGENT_GUIDE.md
|
281
281
|
- Appraisals
|
282
|
+
- CHANGELOG.md
|
282
283
|
- COMMERCIAL_LICENSE_TEMPLATE.md
|
283
284
|
- FEATURES.md
|
284
285
|
- LEGAL_PROTECTION_GUIDE.md
|
@@ -348,6 +349,7 @@ files:
|
|
348
349
|
- rails_ai.gemspec
|
349
350
|
- scripts/security_scanner.rb
|
350
351
|
- setup_monitoring.sh
|
352
|
+
- setup_wiki.sh
|
351
353
|
- wiki/API-Documentation.md
|
352
354
|
- wiki/Architecture-Overview.md
|
353
355
|
- wiki/Contributing-Guide.md
|