soka-rails 0.0.1.beta4
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/.rspec +3 -0
- data/.rubocop.yml +367 -0
- data/CHANGELOG.md +41 -0
- data/CLAUDE.md +243 -0
- data/DESIGN.md +957 -0
- data/LICENSE +21 -0
- data/README.md +420 -0
- data/REQUIREMENT.md +308 -0
- data/Rakefile +12 -0
- data/SPEC.md +420 -0
- data/app/soka/agents/application_agent.rb +5 -0
- data/app/soka/tools/application_tool.rb +5 -0
- data/lib/generators/soka/agent/agent_generator.rb +60 -0
- data/lib/generators/soka/agent/templates/agent.rb.tt +25 -0
- data/lib/generators/soka/agent/templates/agent_spec.rb.tt +31 -0
- data/lib/generators/soka/install/install_generator.rb +39 -0
- data/lib/generators/soka/install/templates/application_agent.rb +5 -0
- data/lib/generators/soka/install/templates/application_tool.rb +5 -0
- data/lib/generators/soka/install/templates/soka.rb +31 -0
- data/lib/generators/soka/tool/templates/tool.rb.tt +26 -0
- data/lib/generators/soka/tool/templates/tool_spec.rb.tt +48 -0
- data/lib/generators/soka/tool/tool_generator.rb +68 -0
- data/lib/soka/rails/agent_extensions.rb +42 -0
- data/lib/soka/rails/configuration.rb +65 -0
- data/lib/soka/rails/errors.rb +73 -0
- data/lib/soka/rails/railtie.rb +15 -0
- data/lib/soka/rails/rspec.rb +29 -0
- data/lib/soka/rails/test_helpers.rb +117 -0
- data/lib/soka/rails/version.rb +7 -0
- data/lib/soka/rails.rb +24 -0
- data/lib/soka_rails.rb +11 -0
- metadata +124 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 jiunjiun
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,420 @@
|
|
1
|
+
# Soka Rails
|
2
|
+
|
3
|
+
<p align="center">
|
4
|
+
<strong>Rails Integration for Soka AI Agent Framework</strong>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<p align="center">
|
8
|
+
<a href="#features">Features</a> •
|
9
|
+
<a href="#installation">Installation</a> •
|
10
|
+
<a href="#quick-start">Quick Start</a> •
|
11
|
+
<a href="#usage">Usage</a> •
|
12
|
+
<a href="#generators">Generators</a> •
|
13
|
+
<a href="#testing">Testing</a> •
|
14
|
+
<a href="#contributing">Contributing</a>
|
15
|
+
</p>
|
16
|
+
|
17
|
+
Soka Rails is a Rails integration package for the Soka AI Agent Framework, providing seamless integration with the Rails ecosystem. It follows Rails conventions and best practices, making it easy for developers to use AI Agents in their Rails applications.
|
18
|
+
|
19
|
+
## Features
|
20
|
+
|
21
|
+
- 🚂 **Native Rails Integration**: Following Rails conventions and best practices
|
22
|
+
- 📁 **Auto-loading Support**: Automatically loads the `app/soka` directory
|
23
|
+
- 🛠️ **Generator Support**: Quickly generate Agent and Tool templates
|
24
|
+
- ⚙️ **Rails Configuration Integration**: Uses Rails' configuration system
|
25
|
+
- 🧪 **Rails Testing Integration**: Seamless integration with RSpec
|
26
|
+
- 🔄 **Rails Lifecycle Hooks**: Integrates with Rails logging and error tracking
|
27
|
+
- 💾 **Session Memory Support**: Store conversation history in Rails sessions
|
28
|
+
- 🔐 **Authentication Integration**: Works with Rails authentication systems
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Add the following to your Gemfile:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
gem 'soka-rails'
|
36
|
+
```
|
37
|
+
|
38
|
+
Then execute:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
bundle install
|
42
|
+
```
|
43
|
+
|
44
|
+
Run the installation generator:
|
45
|
+
|
46
|
+
```bash
|
47
|
+
rails generate soka:install
|
48
|
+
```
|
49
|
+
|
50
|
+
This will generate:
|
51
|
+
- `config/initializers/soka.rb` - Main configuration file
|
52
|
+
- `app/soka/agents/application_agent.rb` - Base Agent class
|
53
|
+
- `app/soka/tools/application_tool.rb` - Base Tool class
|
54
|
+
|
55
|
+
## Quick Start
|
56
|
+
|
57
|
+
### 1. Configure API Keys
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# config/initializers/soka.rb
|
61
|
+
Soka::Rails.configure do |config|
|
62
|
+
config.ai do |ai|
|
63
|
+
ai.provider = ENV.fetch('SOKA_PROVIDER', :gemini)
|
64
|
+
ai.model = ENV.fetch('SOKA_MODEL', 'gemini-2.5-flash-lite')
|
65
|
+
ai.api_key = ENV['SOKA_API_KEY']
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
### 2. Create an Agent
|
71
|
+
|
72
|
+
```bash
|
73
|
+
rails generate soka:agent customer_support
|
74
|
+
```
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
# app/soka/agents/customer_support_agent.rb
|
78
|
+
class CustomerSupportAgent < ApplicationAgent
|
79
|
+
tool OrderLookupTool
|
80
|
+
tool UserInfoTool
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
### 3. Use in Controller
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class ConversationsController < ApplicationController
|
88
|
+
def create
|
89
|
+
agent = CustomerSupportAgent.new
|
90
|
+
result = agent.run(params[:message])
|
91
|
+
|
92
|
+
render json: {
|
93
|
+
answer: result.final_answer,
|
94
|
+
confidence: result.confidence_score
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
## Usage
|
101
|
+
|
102
|
+
### Directory Structure
|
103
|
+
|
104
|
+
```
|
105
|
+
rails-app/
|
106
|
+
├── app/
|
107
|
+
│ └── soka/
|
108
|
+
│ ├── agents/ # Agent definitions
|
109
|
+
│ │ ├── application_agent.rb
|
110
|
+
│ │ └── customer_support_agent.rb
|
111
|
+
│ └── tools/ # Tool definitions
|
112
|
+
│ ├── application_tool.rb
|
113
|
+
│ └── order_lookup_tool.rb
|
114
|
+
└── config/
|
115
|
+
└── initializers/
|
116
|
+
└── soka.rb # Global configuration
|
117
|
+
```
|
118
|
+
|
119
|
+
### Creating Agents
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class WeatherAgent < ApplicationAgent
|
123
|
+
# Configure AI settings
|
124
|
+
provider :gemini
|
125
|
+
model 'gemini-2.5-flash-lite'
|
126
|
+
max_iterations 10
|
127
|
+
timeout 30.seconds
|
128
|
+
|
129
|
+
# Register tools
|
130
|
+
tool WeatherApiTool
|
131
|
+
tool LocationTool
|
132
|
+
|
133
|
+
# Rails integration hooks
|
134
|
+
before_action :log_request
|
135
|
+
on_error :notify_error_service
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def log_request(input)
|
140
|
+
Rails.logger.info "[WeatherAgent] Processing: #{input}"
|
141
|
+
end
|
142
|
+
|
143
|
+
def notify_error_service(error, context)
|
144
|
+
Rails.error.report(error, context: context)
|
145
|
+
:continue
|
146
|
+
end
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
### Creating Tools
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
class OrderLookupTool < ApplicationTool
|
154
|
+
desc "Look up order information"
|
155
|
+
|
156
|
+
params do
|
157
|
+
requires :order_id, String, desc: "Order ID"
|
158
|
+
optional :include_items, :boolean, desc: "Include order items", default: false
|
159
|
+
end
|
160
|
+
|
161
|
+
def call(order_id:, include_items: false)
|
162
|
+
order = Order.find_by(id: order_id)
|
163
|
+
return { error: "Order not found" } unless order
|
164
|
+
|
165
|
+
data = {
|
166
|
+
id: order.id,
|
167
|
+
status: order.status,
|
168
|
+
total: order.total,
|
169
|
+
created_at: order.created_at
|
170
|
+
}
|
171
|
+
|
172
|
+
data[:items] = order.items if include_items
|
173
|
+
data
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
### Session Memory
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
class ConversationsController < ApplicationController
|
182
|
+
def create
|
183
|
+
# Load memory from session
|
184
|
+
memory = session[:conversation_memory] || []
|
185
|
+
|
186
|
+
agent = CustomerSupportAgent.new(memory: memory)
|
187
|
+
result = agent.run(params[:message])
|
188
|
+
|
189
|
+
# Update session memory
|
190
|
+
session[:conversation_memory] = agent.memory.to_a
|
191
|
+
|
192
|
+
render json: { answer: result.final_answer }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
### Event Streaming
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
class ConversationsController < ApplicationController
|
201
|
+
include ActionController::Live
|
202
|
+
|
203
|
+
def stream
|
204
|
+
response.headers['Content-Type'] = 'text/event-stream'
|
205
|
+
agent = CustomerSupportAgent.new
|
206
|
+
|
207
|
+
agent.run(params[:message]) do |event|
|
208
|
+
response.stream.write("event: #{event.type}\n")
|
209
|
+
response.stream.write("data: #{event.content.to_json}\n\n")
|
210
|
+
end
|
211
|
+
ensure
|
212
|
+
response.stream.close
|
213
|
+
end
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
## Generators
|
218
|
+
|
219
|
+
### Install Generator
|
220
|
+
|
221
|
+
```bash
|
222
|
+
rails generate soka:install
|
223
|
+
```
|
224
|
+
|
225
|
+
### Agent Generator
|
226
|
+
|
227
|
+
```bash
|
228
|
+
# Basic usage
|
229
|
+
rails generate soka:agent weather
|
230
|
+
|
231
|
+
# With tools - automatically registers tools in the agent
|
232
|
+
rails generate soka:agent weather forecast temperature humidity
|
233
|
+
```
|
234
|
+
|
235
|
+
Creates `app/soka/agents/weather_agent.rb` with a template structure.
|
236
|
+
|
237
|
+
When tools are specified, the generated agent will include them:
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
class WeatherAgent < ApplicationAgent
|
241
|
+
# Tool registration
|
242
|
+
tool ForecastTool
|
243
|
+
tool TemperatureTool
|
244
|
+
tool HumidityTool
|
245
|
+
|
246
|
+
# Configuration
|
247
|
+
# max_iterations 10
|
248
|
+
# timeout 30
|
249
|
+
end
|
250
|
+
```
|
251
|
+
|
252
|
+
### Tool Generator
|
253
|
+
|
254
|
+
```bash
|
255
|
+
# Basic usage
|
256
|
+
rails generate soka:tool weather_api
|
257
|
+
|
258
|
+
# With parameters - automatically generates parameter definitions
|
259
|
+
rails generate soka:tool weather_api location:string units:string timeout:integer
|
260
|
+
```
|
261
|
+
|
262
|
+
Creates `app/soka/tools/weather_api_tool.rb` with parameter definitions.
|
263
|
+
|
264
|
+
When parameters are specified, the generated tool will include them:
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
class WeatherApiTool < ApplicationTool
|
268
|
+
desc 'Description of your tool'
|
269
|
+
|
270
|
+
params do
|
271
|
+
requires :location, String, desc: 'Location'
|
272
|
+
requires :units, String, desc: 'Units'
|
273
|
+
requires :timeout, Integer, desc: 'Timeout'
|
274
|
+
end
|
275
|
+
|
276
|
+
def call(**params)
|
277
|
+
# Implement your tool logic here
|
278
|
+
end
|
279
|
+
end
|
280
|
+
```
|
281
|
+
|
282
|
+
## Testing
|
283
|
+
|
284
|
+
### RSpec Configuration
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
# spec/rails_helper.rb
|
288
|
+
require 'soka/rails/rspec'
|
289
|
+
|
290
|
+
RSpec.configure do |config|
|
291
|
+
config.include Soka::Rails::TestHelpers, type: :agent
|
292
|
+
config.include Soka::Rails::TestHelpers, type: :tool
|
293
|
+
end
|
294
|
+
```
|
295
|
+
|
296
|
+
### Testing Agents
|
297
|
+
|
298
|
+
```ruby
|
299
|
+
RSpec.describe WeatherAgent, type: :agent do
|
300
|
+
let(:agent) { described_class.new }
|
301
|
+
|
302
|
+
before do
|
303
|
+
mock_ai_response(
|
304
|
+
final_answer: "Today in Tokyo it's sunny with 28°C"
|
305
|
+
)
|
306
|
+
end
|
307
|
+
|
308
|
+
it "responds to weather queries" do
|
309
|
+
result = agent.run("What's the weather in Tokyo?")
|
310
|
+
|
311
|
+
expect(result).to be_successful
|
312
|
+
expect(result.final_answer).to include("28°C")
|
313
|
+
end
|
314
|
+
end
|
315
|
+
```
|
316
|
+
|
317
|
+
### Testing Tools
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
RSpec.describe OrderLookupTool, type: :tool do
|
321
|
+
let(:tool) { described_class.new }
|
322
|
+
let(:order) { create(:order, id: "123", status: "delivered") }
|
323
|
+
|
324
|
+
it "finds existing orders" do
|
325
|
+
result = tool.call(order_id: order.id)
|
326
|
+
|
327
|
+
expect(result[:status]).to eq("delivered")
|
328
|
+
expect(result[:id]).to eq("123")
|
329
|
+
end
|
330
|
+
|
331
|
+
it "handles missing orders" do
|
332
|
+
result = tool.call(order_id: "nonexistent")
|
333
|
+
|
334
|
+
expect(result[:error]).to include("not found")
|
335
|
+
end
|
336
|
+
end
|
337
|
+
```
|
338
|
+
|
339
|
+
## Rails-Specific Tools
|
340
|
+
|
341
|
+
### RailsInfoTool
|
342
|
+
|
343
|
+
A built-in tool for accessing Rails application information:
|
344
|
+
|
345
|
+
```ruby
|
346
|
+
class RailsInfoTool < ApplicationTool
|
347
|
+
desc "Get Rails application information"
|
348
|
+
|
349
|
+
params do
|
350
|
+
requires :info_type, String, desc: "Type of information",
|
351
|
+
validates: { inclusion: { in: %w[routes version environment config] } }
|
352
|
+
end
|
353
|
+
|
354
|
+
def call(info_type:)
|
355
|
+
case info_type
|
356
|
+
when 'routes'
|
357
|
+
# Returns application routes
|
358
|
+
when 'version'
|
359
|
+
# Returns Rails and Ruby versions
|
360
|
+
when 'environment'
|
361
|
+
# Returns environment information
|
362
|
+
when 'config'
|
363
|
+
# Returns safe configuration values
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
```
|
368
|
+
|
369
|
+
## Configuration
|
370
|
+
|
371
|
+
### Environment-based Configuration
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
Soka::Rails.configure do |config|
|
375
|
+
config.ai do |ai|
|
376
|
+
ai.provider = ENV.fetch('SOKA_PROVIDER', :gemini)
|
377
|
+
ai.model = ENV.fetch('SOKA_MODEL', 'gemini-2.5-flash-lite')
|
378
|
+
ai.api_key = ENV['SOKA_API_KEY']
|
379
|
+
end
|
380
|
+
|
381
|
+
config.performance do |perf|
|
382
|
+
perf.max_iterations = Rails.env.production? ? 10 : 5
|
383
|
+
perf.timeout = 30.seconds
|
384
|
+
end
|
385
|
+
end
|
386
|
+
```
|
387
|
+
|
388
|
+
## Compatibility
|
389
|
+
|
390
|
+
- Ruby: >= 3.4
|
391
|
+
- Rails: >= 7.0
|
392
|
+
- Soka: >= 1.0
|
393
|
+
|
394
|
+
## Contributing
|
395
|
+
|
396
|
+
We welcome all forms of contributions!
|
397
|
+
|
398
|
+
1. Fork the project
|
399
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
400
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
401
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
402
|
+
5. Open a Pull Request
|
403
|
+
|
404
|
+
Please ensure:
|
405
|
+
- Add appropriate tests
|
406
|
+
- Update relevant documentation
|
407
|
+
- Follow Rails coding conventions
|
408
|
+
- Pass Rubocop checks
|
409
|
+
|
410
|
+
## License
|
411
|
+
|
412
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
413
|
+
|
414
|
+
---
|
415
|
+
|
416
|
+
<p align="center">
|
417
|
+
Made with ❤️ for the Rails Community<br>
|
418
|
+
Built on top of <a href="https://github.com/jiunjiun/soka">Soka AI Agent Framework</a><br>
|
419
|
+
Created by <a href="https://claude.ai/code">Claude Code</a>
|
420
|
+
</p>
|