rails_console_ai 0.13.0 → 0.15.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +31 -18
- data/app/controllers/rails_console_ai/application_controller.rb +5 -5
- data/app/controllers/rails_console_ai/sessions_controller.rb +1 -1
- data/app/helpers/rails_console_ai/sessions_helper.rb +1 -1
- data/app/models/rails_console_ai/session.rb +2 -2
- data/app/views/layouts/rails_console_ai/application.html.erb +2 -2
- data/config/routes.rb +1 -1
- data/lib/generators/rails_console_ai/install_generator.rb +3 -3
- data/lib/generators/rails_console_ai/templates/initializer.rb +4 -4
- data/lib/rails_console_ai/channel/base.rb +1 -1
- data/lib/rails_console_ai/channel/console.rb +15 -15
- data/lib/rails_console_ai/channel/slack.rb +2 -2
- data/lib/rails_console_ai/configuration.rb +4 -2
- data/lib/rails_console_ai/console_methods.rb +19 -19
- data/lib/rails_console_ai/context_builder.rb +6 -6
- data/lib/rails_console_ai/conversation_engine.rb +29 -29
- data/lib/rails_console_ai/engine.rb +2 -2
- data/lib/rails_console_ai/executor.rb +11 -11
- data/lib/rails_console_ai/providers/anthropic.rb +1 -1
- data/lib/rails_console_ai/providers/base.rb +3 -3
- data/lib/rails_console_ai/providers/bedrock.rb +1 -1
- data/lib/rails_console_ai/providers/local.rb +1 -1
- data/lib/rails_console_ai/providers/openai.rb +1 -1
- data/lib/rails_console_ai/railtie.rb +6 -6
- data/lib/rails_console_ai/repl.rb +1 -1
- data/lib/rails_console_ai/safety_guards.rb +6 -6
- data/lib/rails_console_ai/session_logger.rb +13 -13
- data/lib/rails_console_ai/slack_bot.rb +12 -12
- data/lib/rails_console_ai/storage/base.rb +1 -1
- data/lib/rails_console_ai/storage/file_storage.rb +1 -1
- data/lib/rails_console_ai/tools/code_tools.rb +37 -19
- data/lib/rails_console_ai/tools/memory_tools.rb +4 -4
- data/lib/rails_console_ai/tools/model_tools.rb +1 -1
- data/lib/rails_console_ai/tools/registry.rb +7 -7
- data/lib/rails_console_ai/tools/schema_tools.rb +1 -1
- data/lib/rails_console_ai/version.rb +2 -2
- data/lib/rails_console_ai.rb +14 -14
- data/lib/tasks/rails_console_ai.rake +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f82dc8df360173a57a1152e60a47e7bf59c31b3721658ee590b7d5cb7c765fbd
|
|
4
|
+
data.tar.gz: 942c2df0dda0048784e7cce6911a20685480de5a4c39ae5b1ca0d875d2f6627d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 32edecb4a5c29703ce2ff309fd922c11de57240f98df92072c86f99f3373c3eaeaf689e912960cc60a71cc40e37b2dacf2cea73dd6385cb101f36dd61d913f99
|
|
7
|
+
data.tar.gz: e36e885ad95efcf976ee249c2524348e84b11aa61d447d9680ffeb049b7a6f4628c0e34b5027127e04ac83979259b4e16fea3f7208be2c6645d9bf25cf52bdcf
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.15.0]
|
|
6
|
+
|
|
7
|
+
- Add `config.code_search_paths` to configure searchable code directories
|
|
8
|
+
|
|
9
|
+
## [0.14.0]
|
|
10
|
+
|
|
11
|
+
- Change module name from `RailsConsoleAI` to `RailsConsoleAi`
|
|
12
|
+
|
|
5
13
|
## [0.13.0]
|
|
6
14
|
|
|
7
15
|
- Rename gem from `console_agent` to `rails_console_ai`
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# RailsConsoleAi
|
|
2
2
|
|
|
3
3
|
Claude Code for your Rails Console.
|
|
4
4
|
|
|
@@ -49,7 +49,7 @@ Set your API key in the generated initializer or via env var (`ANTHROPIC_API_KEY
|
|
|
49
49
|
|
|
50
50
|
```ruby
|
|
51
51
|
# config/initializers/rails_console_ai.rb
|
|
52
|
-
|
|
52
|
+
RailsConsoleAi.configure do |config|
|
|
53
53
|
config.api_key = 'sk-ant-...'
|
|
54
54
|
end
|
|
55
55
|
```
|
|
@@ -93,7 +93,7 @@ Say "think harder" in any query to auto-upgrade to the thinking model for that s
|
|
|
93
93
|
|
|
94
94
|
## Features
|
|
95
95
|
|
|
96
|
-
- **Tool use** — AI introspects your schema, models, files, and code to write accurate queries
|
|
96
|
+
- **Tool use** — AI introspects your schema, models, files (Ruby, ERB, HTML, JS, CSS, YAML, etc), and code to write accurate queries
|
|
97
97
|
- **Multi-step plans** — complex tasks are broken into steps, executed sequentially with `step1`/`step2` references
|
|
98
98
|
- **Two-tier models** — defaults to Sonnet for speed/cost; `/think` upgrades to Opus when you need it
|
|
99
99
|
- **Cost tracking** — `/cost` shows per-model token usage and estimated spend
|
|
@@ -112,7 +112,7 @@ Safety guards prevent AI-generated code from causing side effects. When a guard
|
|
|
112
112
|
### Built-in Guards
|
|
113
113
|
|
|
114
114
|
```ruby
|
|
115
|
-
|
|
115
|
+
RailsConsoleAi.configure do |config|
|
|
116
116
|
config.use_builtin_safety_guard :database_writes # blocks INSERT/UPDATE/DELETE/DROP/etc.
|
|
117
117
|
config.use_builtin_safety_guard :http_mutations # blocks POST/PUT/PATCH/DELETE via Net::HTTP
|
|
118
118
|
config.use_builtin_safety_guard :mailers # disables ActionMailer delivery
|
|
@@ -128,17 +128,17 @@ end
|
|
|
128
128
|
Write your own guards using the around-block pattern:
|
|
129
129
|
|
|
130
130
|
```ruby
|
|
131
|
-
|
|
131
|
+
RailsConsoleAi.configure do |config|
|
|
132
132
|
config.safety_guard :jobs do |&execute|
|
|
133
133
|
Sidekiq::Testing.fake! { execute.call }
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
Raise `
|
|
138
|
+
Raise `RailsConsoleAi::SafetyError` in your app code to trigger the safe mode prompt:
|
|
139
139
|
|
|
140
140
|
```ruby
|
|
141
|
-
raise
|
|
141
|
+
raise RailsConsoleAi::SafetyError, "Stripe charge blocked"
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
### Toggling Safe Mode
|
|
@@ -149,12 +149,12 @@ raise RailsConsoleAI::SafetyError, "Stripe charge blocked"
|
|
|
149
149
|
|
|
150
150
|
## LLM Providers
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
RailsConsoleAi supports four LLM providers. Each uses a two-tier model system: a default model for speed/cost, and a thinking model activated via `/think` or by saying "think harder".
|
|
153
153
|
|
|
154
154
|
### Anthropic (default)
|
|
155
155
|
|
|
156
156
|
```ruby
|
|
157
|
-
|
|
157
|
+
RailsConsoleAi.configure do |config|
|
|
158
158
|
config.provider = :anthropic
|
|
159
159
|
config.api_key = 'sk-ant-...' # or set ANTHROPIC_API_KEY env var
|
|
160
160
|
end
|
|
@@ -165,7 +165,7 @@ Default model: `claude-sonnet-4-6`. Thinking model: `claude-opus-4-6`. Prompt ca
|
|
|
165
165
|
### OpenAI
|
|
166
166
|
|
|
167
167
|
```ruby
|
|
168
|
-
|
|
168
|
+
RailsConsoleAi.configure do |config|
|
|
169
169
|
config.provider = :openai
|
|
170
170
|
config.api_key = 'sk-...' # or set OPENAI_API_KEY env var
|
|
171
171
|
end
|
|
@@ -183,7 +183,7 @@ gem 'aws-sdk-bedrockruntime'
|
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
```ruby
|
|
186
|
-
|
|
186
|
+
RailsConsoleAi.configure do |config|
|
|
187
187
|
config.provider = :bedrock
|
|
188
188
|
config.bedrock_region = 'us-east-1'
|
|
189
189
|
# config.model = 'us.anthropic.claude-sonnet-4-6' # default
|
|
@@ -211,7 +211,7 @@ Prompt caching is automatically enabled for Anthropic models on Bedrock, reducin
|
|
|
211
211
|
Run against a local model server. No API key required.
|
|
212
212
|
|
|
213
213
|
```ruby
|
|
214
|
-
|
|
214
|
+
RailsConsoleAi.configure do |config|
|
|
215
215
|
config.provider = :local
|
|
216
216
|
config.local_url = 'http://localhost:11434'
|
|
217
217
|
config.local_model = 'qwen2.5:7b'
|
|
@@ -224,16 +224,29 @@ Timeout is automatically raised to 300s minimum for local models to account for
|
|
|
224
224
|
## Configuration
|
|
225
225
|
|
|
226
226
|
```ruby
|
|
227
|
-
|
|
227
|
+
RailsConsoleAi.configure do |config|
|
|
228
228
|
config.provider = :anthropic # :anthropic, :openai, :bedrock, :local
|
|
229
229
|
config.auto_execute = false # true to skip confirmations
|
|
230
230
|
config.session_logging = true # requires ai_setup
|
|
231
231
|
config.temperature = 0.2
|
|
232
232
|
config.timeout = 30 # HTTP timeout in seconds
|
|
233
233
|
config.max_tool_rounds = 200 # safety cap on tool-use loops
|
|
234
|
+
config.code_search_paths = %w[app] # directories for list_files / search_code
|
|
234
235
|
end
|
|
235
236
|
```
|
|
236
237
|
|
|
238
|
+
### Code Search Paths
|
|
239
|
+
|
|
240
|
+
By default, `list_files` and `search_code` only look in `app/`. If your project has code in other directories (e.g. a frontend in `public/portal`, or shared code in `lib`), add them:
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
RailsConsoleAi.configure do |config|
|
|
244
|
+
config.code_search_paths = %w[app lib public/portal]
|
|
245
|
+
end
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The tools search all configured paths when no explicit directory is passed. You can still pass a specific directory to either tool to override this.
|
|
249
|
+
|
|
237
250
|
## Web UI Authentication
|
|
238
251
|
|
|
239
252
|
The engine mounts a session viewer at `/rails_console_ai`. By default it's open — you can protect it with basic auth or a custom authentication function.
|
|
@@ -241,7 +254,7 @@ The engine mounts a session viewer at `/rails_console_ai`. By default it's open
|
|
|
241
254
|
### Basic Auth
|
|
242
255
|
|
|
243
256
|
```ruby
|
|
244
|
-
|
|
257
|
+
RailsConsoleAi.configure do |config|
|
|
245
258
|
config.admin_username = 'admin'
|
|
246
259
|
config.admin_password = ENV['CONSOLE_AGENT_PASSWORD']
|
|
247
260
|
end
|
|
@@ -252,7 +265,7 @@ end
|
|
|
252
265
|
For apps with their own auth system, pass a proc to `authenticate`. It runs in the controller context, so you have access to `session`, `request`, `redirect_to`, etc.
|
|
253
266
|
|
|
254
267
|
```ruby
|
|
255
|
-
|
|
268
|
+
RailsConsoleAi.configure do |config|
|
|
256
269
|
config.authenticate = proc {
|
|
257
270
|
user = User.find_by(id: session[:user_id])
|
|
258
271
|
unless user&.admin?
|
|
@@ -266,11 +279,11 @@ When `authenticate` is set, `admin_username` / `admin_password` are ignored.
|
|
|
266
279
|
|
|
267
280
|
## Additional Channels
|
|
268
281
|
|
|
269
|
-
|
|
282
|
+
RailsConsoleAi can run through different channels beyond the Rails console. Each channel is a separate process that connects the same AI engine to a different interface.
|
|
270
283
|
|
|
271
284
|
### Slack
|
|
272
285
|
|
|
273
|
-
Run
|
|
286
|
+
Run RailsConsoleAi as a Slack bot. Each Slack thread becomes an independent AI session with full tool use, multi-step plans, and safety guards always on.
|
|
274
287
|
|
|
275
288
|
#### Slack App Setup
|
|
276
289
|
|
|
@@ -299,7 +312,7 @@ Run RailsConsoleAI as a Slack bot. Each Slack thread becomes an independent AI s
|
|
|
299
312
|
#### Configuration
|
|
300
313
|
|
|
301
314
|
```ruby
|
|
302
|
-
|
|
315
|
+
RailsConsoleAi.configure do |config|
|
|
303
316
|
config.slack_bot_token = ENV['SLACK_BOT_TOKEN'] # xoxb-...
|
|
304
317
|
config.slack_app_token = ENV['SLACK_APP_TOKEN'] # xapp-...
|
|
305
318
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module RailsConsoleAi
|
|
2
2
|
class ApplicationController < ActionController::Base
|
|
3
3
|
protect_from_forgery with: :exception
|
|
4
4
|
|
|
@@ -7,18 +7,18 @@ module RailsConsoleAI
|
|
|
7
7
|
private
|
|
8
8
|
|
|
9
9
|
def rails_console_ai_authenticate!
|
|
10
|
-
if (auth =
|
|
10
|
+
if (auth = RailsConsoleAi.configuration.authenticate)
|
|
11
11
|
instance_exec(&auth)
|
|
12
12
|
else
|
|
13
|
-
username =
|
|
14
|
-
password =
|
|
13
|
+
username = RailsConsoleAi.configuration.admin_username
|
|
14
|
+
password = RailsConsoleAi.configuration.admin_password
|
|
15
15
|
|
|
16
16
|
unless username && password
|
|
17
17
|
head :unauthorized
|
|
18
18
|
return
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
authenticate_or_request_with_http_basic('
|
|
21
|
+
authenticate_or_request_with_http_basic('RailsConsoleAi Admin') do |u, p|
|
|
22
22
|
ActiveSupport::SecurityUtils.secure_compare(u, username) &
|
|
23
23
|
ActiveSupport::SecurityUtils.secure_compare(p, password)
|
|
24
24
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module RailsConsoleAi
|
|
2
2
|
class Session < ActiveRecord::Base
|
|
3
3
|
self.table_name = 'rails_console_ai_sessions'
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ module RailsConsoleAI
|
|
|
11
11
|
scope :search, ->(q) { where("name LIKE ? OR query LIKE ?", "%#{q}%", "%#{q}%") }
|
|
12
12
|
|
|
13
13
|
def self.connection
|
|
14
|
-
klass =
|
|
14
|
+
klass = RailsConsoleAi.configuration.connection_class
|
|
15
15
|
if klass
|
|
16
16
|
klass = Object.const_get(klass) if klass.is_a?(String)
|
|
17
17
|
klass.connection
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
|
-
<title>
|
|
4
|
+
<title>RailsConsoleAi Admin</title>
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<style>
|
|
7
7
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
</head>
|
|
75
75
|
<body>
|
|
76
76
|
<div class="header">
|
|
77
|
-
<h1>
|
|
77
|
+
<h1>RailsConsoleAi Admin</h1>
|
|
78
78
|
<a href="<%= rails_console_ai.root_path %>">Sessions</a>
|
|
79
79
|
</div>
|
|
80
80
|
<div class="container">
|
data/config/routes.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
require 'rails/generators'
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module RailsConsoleAi
|
|
4
4
|
module Generators
|
|
5
5
|
class InstallGenerator < Rails::Generators::Base
|
|
6
6
|
source_root File.expand_path('templates', __dir__)
|
|
7
|
-
desc 'Creates a
|
|
7
|
+
desc 'Creates a RailsConsoleAi initializer in config/initializers/'
|
|
8
8
|
|
|
9
9
|
def copy_initializer
|
|
10
10
|
template 'initializer.rb', 'config/initializers/rails_console_ai.rb'
|
|
@@ -12,7 +12,7 @@ module RailsConsoleAI
|
|
|
12
12
|
|
|
13
13
|
def show_readme
|
|
14
14
|
say ''
|
|
15
|
-
say '
|
|
15
|
+
say 'RailsConsoleAi installed!', :green
|
|
16
16
|
say ''
|
|
17
17
|
say 'Next steps:'
|
|
18
18
|
say ' 1. Set your API key: export ANTHROPIC_API_KEY=sk-...'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
RailsConsoleAi.configure do |config|
|
|
2
2
|
# LLM provider: :anthropic, :openai, or :local
|
|
3
3
|
config.provider = :anthropic
|
|
4
4
|
|
|
@@ -42,14 +42,14 @@ RailsConsoleAI.configure do |config|
|
|
|
42
42
|
# config.debug = true
|
|
43
43
|
|
|
44
44
|
# Session logging: persist AI sessions to the database
|
|
45
|
-
# Run
|
|
45
|
+
# Run RailsConsoleAi.setup! in the Rails console to create the table
|
|
46
46
|
config.session_logging = true
|
|
47
47
|
|
|
48
|
-
# Database connection for
|
|
48
|
+
# Database connection for RailsConsoleAi tables (default: ActiveRecord::Base)
|
|
49
49
|
# Set to a class that responds to .connection if tables live on a different DB
|
|
50
50
|
# config.connection_class = Sharding::CentralizedModel
|
|
51
51
|
|
|
52
|
-
# Admin UI credentials (mount
|
|
52
|
+
# Admin UI credentials (mount RailsConsoleAi::Engine => '/rails_console_ai' in routes.rb)
|
|
53
53
|
# When nil, all requests are denied. Set credentials or use config.authenticate.
|
|
54
54
|
# config.admin_username = 'admin'
|
|
55
55
|
# config.admin_password = 'changeme'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'readline'
|
|
2
2
|
require 'rails_console_ai/channel/base'
|
|
3
3
|
|
|
4
|
-
module
|
|
4
|
+
module RailsConsoleAi
|
|
5
5
|
module Channel
|
|
6
6
|
class Console < Base
|
|
7
7
|
attr_reader :real_stdout
|
|
@@ -71,7 +71,7 @@ module RailsConsoleAI
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def user_identity
|
|
74
|
-
|
|
74
|
+
RailsConsoleAi.current_user
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def mode
|
|
@@ -154,10 +154,10 @@ module RailsConsoleAI
|
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
def run_interactive_loop
|
|
157
|
-
auto =
|
|
158
|
-
guards =
|
|
157
|
+
auto = RailsConsoleAi.configuration.auto_execute
|
|
158
|
+
guards = RailsConsoleAi.configuration.safety_guards
|
|
159
159
|
name_display = @engine.session_name ? " (#{@engine.session_name})" : ""
|
|
160
|
-
@real_stdout.puts "\e[
|
|
160
|
+
@real_stdout.puts "\e[36mRailsConsoleAi interactive mode#{name_display}. Type 'exit' or 'quit' to leave.\e[0m"
|
|
161
161
|
safe_info = guards.empty? ? '' : " | Safe mode: #{guards.enabled? ? 'ON' : 'OFF'} (/danger to toggle)"
|
|
162
162
|
@real_stdout.puts "\e[2m Auto-execute: #{auto ? 'ON' : 'OFF'} (Shift-Tab or /auto to toggle)#{safe_info} | > code | /usage | /cost | /compact | /think | /name <label>\e[0m"
|
|
163
163
|
|
|
@@ -220,7 +220,7 @@ module RailsConsoleAI
|
|
|
220
220
|
display_exit_info
|
|
221
221
|
rescue => e
|
|
222
222
|
$stdout = @real_stdout if @real_stdout
|
|
223
|
-
$stderr.puts "\e[
|
|
223
|
+
$stderr.puts "\e[31mRailsConsoleAi Error: #{e.class}: #{e.message}\e[0m"
|
|
224
224
|
end
|
|
225
225
|
|
|
226
226
|
def handle_slash_command(input)
|
|
@@ -228,8 +228,8 @@ module RailsConsoleAI
|
|
|
228
228
|
when '?', '/'
|
|
229
229
|
display_help
|
|
230
230
|
when '/auto'
|
|
231
|
-
|
|
232
|
-
mode =
|
|
231
|
+
RailsConsoleAi.configuration.auto_execute = !RailsConsoleAi.configuration.auto_execute
|
|
232
|
+
mode = RailsConsoleAi.configuration.auto_execute ? 'ON' : 'OFF'
|
|
233
233
|
@real_stdout.puts "\e[36m Auto-execute: #{mode}\e[0m"
|
|
234
234
|
when '/danger'
|
|
235
235
|
toggle_danger
|
|
@@ -238,8 +238,8 @@ module RailsConsoleAI
|
|
|
238
238
|
when '/usage'
|
|
239
239
|
@engine.display_session_summary
|
|
240
240
|
when '/debug'
|
|
241
|
-
|
|
242
|
-
mode =
|
|
241
|
+
RailsConsoleAi.configuration.debug = !RailsConsoleAi.configuration.debug
|
|
242
|
+
mode = RailsConsoleAi.configuration.debug ? 'ON' : 'OFF'
|
|
243
243
|
@real_stdout.puts "\e[36m Debug: #{mode}\e[0m"
|
|
244
244
|
when '/compact'
|
|
245
245
|
@engine.compact_history
|
|
@@ -276,7 +276,7 @@ module RailsConsoleAI
|
|
|
276
276
|
end
|
|
277
277
|
|
|
278
278
|
def toggle_danger
|
|
279
|
-
guards =
|
|
279
|
+
guards = RailsConsoleAi.configuration.safety_guards
|
|
280
280
|
if guards.empty?
|
|
281
281
|
@real_stdout.puts "\e[33m No safety guards configured.\e[0m"
|
|
282
282
|
elsif guards.enabled?
|
|
@@ -289,7 +289,7 @@ module RailsConsoleAI
|
|
|
289
289
|
end
|
|
290
290
|
|
|
291
291
|
def display_safe_status
|
|
292
|
-
guards =
|
|
292
|
+
guards = RailsConsoleAi.configuration.safety_guards
|
|
293
293
|
if guards.empty?
|
|
294
294
|
@real_stdout.puts "\e[33m No safety guards configured.\e[0m"
|
|
295
295
|
else
|
|
@@ -323,8 +323,8 @@ module RailsConsoleAI
|
|
|
323
323
|
end
|
|
324
324
|
|
|
325
325
|
def display_help
|
|
326
|
-
auto =
|
|
327
|
-
guards =
|
|
326
|
+
auto = RailsConsoleAi.configuration.auto_execute ? 'ON' : 'OFF'
|
|
327
|
+
guards = RailsConsoleAi.configuration.safety_guards
|
|
328
328
|
@real_stdout.puts "\e[36m Commands:\e[0m"
|
|
329
329
|
@real_stdout.puts "\e[2m /auto Toggle auto-execute (currently #{auto}) (Shift-Tab)\e[0m"
|
|
330
330
|
unless guards.empty?
|
|
@@ -357,7 +357,7 @@ module RailsConsoleAI
|
|
|
357
357
|
$stdout.puts "\e[2m Resume it: ai_resume #{session_id}\e[0m"
|
|
358
358
|
end
|
|
359
359
|
end
|
|
360
|
-
$stdout.puts "\e[36mLeft
|
|
360
|
+
$stdout.puts "\e[36mLeft RailsConsoleAi interactive mode.\e[0m"
|
|
361
361
|
end
|
|
362
362
|
|
|
363
363
|
# --- Terminal helpers ---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'rails_console_ai/channel/base'
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module RailsConsoleAi
|
|
4
4
|
module Channel
|
|
5
5
|
class Slack < Base
|
|
6
6
|
ANSI_REGEX = /\e\[[0-9;]*m/
|
|
@@ -167,7 +167,7 @@ module RailsConsoleAI
|
|
|
167
167
|
text: text
|
|
168
168
|
)
|
|
169
169
|
rescue => e
|
|
170
|
-
|
|
170
|
+
RailsConsoleAi.logger.error("Slack post failed: #{e.message}")
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
def random_thinking_message
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module RailsConsoleAi
|
|
2
2
|
class Configuration
|
|
3
3
|
PROVIDERS = %i[anthropic openai local bedrock].freeze
|
|
4
4
|
|
|
@@ -27,7 +27,8 @@ module RailsConsoleAI
|
|
|
27
27
|
:authenticate,
|
|
28
28
|
:slack_bot_token, :slack_app_token, :slack_channel_ids, :slack_allowed_usernames,
|
|
29
29
|
:local_url, :local_model, :local_api_key,
|
|
30
|
-
:bedrock_region
|
|
30
|
+
:bedrock_region,
|
|
31
|
+
:code_search_paths
|
|
31
32
|
|
|
32
33
|
def initialize
|
|
33
34
|
@provider = :anthropic
|
|
@@ -56,6 +57,7 @@ module RailsConsoleAI
|
|
|
56
57
|
@local_model = 'qwen2.5:7b'
|
|
57
58
|
@local_api_key = nil
|
|
58
59
|
@bedrock_region = nil
|
|
60
|
+
@code_search_paths = %w[app]
|
|
59
61
|
end
|
|
60
62
|
|
|
61
63
|
def safety_guards
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
module
|
|
1
|
+
module RailsConsoleAi
|
|
2
2
|
module ConsoleMethods
|
|
3
3
|
def ai_status
|
|
4
|
-
|
|
4
|
+
RailsConsoleAi.status
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def ai_memories(n = nil)
|
|
8
8
|
require 'yaml'
|
|
9
9
|
require 'rails_console_ai/tools/memory_tools'
|
|
10
|
-
storage =
|
|
10
|
+
storage = RailsConsoleAi.storage
|
|
11
11
|
keys = storage.list('memories/*.md').sort
|
|
12
12
|
|
|
13
13
|
if keys.empty?
|
|
@@ -48,7 +48,7 @@ module RailsConsoleAI
|
|
|
48
48
|
|
|
49
49
|
def ai_sessions(n = 10, search: nil)
|
|
50
50
|
require 'rails_console_ai/session_logger'
|
|
51
|
-
session_class = Object.const_get('
|
|
51
|
+
session_class = Object.const_get('RailsConsoleAi::Session')
|
|
52
52
|
|
|
53
53
|
scope = session_class.recent
|
|
54
54
|
scope = scope.search(search) if search
|
|
@@ -80,7 +80,7 @@ module RailsConsoleAI
|
|
|
80
80
|
$stdout.puts "\e[2mUse ai_sessions(n, search: \"term\") to filter.\e[0m"
|
|
81
81
|
nil
|
|
82
82
|
rescue => e
|
|
83
|
-
$stderr.puts "\e[
|
|
83
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
84
84
|
nil
|
|
85
85
|
end
|
|
86
86
|
|
|
@@ -96,8 +96,8 @@ module RailsConsoleAI
|
|
|
96
96
|
session = if identifier
|
|
97
97
|
__find_session(identifier)
|
|
98
98
|
else
|
|
99
|
-
session_class = Object.const_get('
|
|
100
|
-
session_class.where(mode: 'interactive', user_name:
|
|
99
|
+
session_class = Object.const_get('RailsConsoleAi::Session')
|
|
100
|
+
session_class.where(mode: 'interactive', user_name: RailsConsoleAi.current_user).recent.first
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
unless session
|
|
@@ -109,7 +109,7 @@ module RailsConsoleAI
|
|
|
109
109
|
repl = Repl.new(__rails_console_ai_binding)
|
|
110
110
|
repl.resume(session)
|
|
111
111
|
rescue => e
|
|
112
|
-
$stderr.puts "\e[
|
|
112
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
113
113
|
nil
|
|
114
114
|
end
|
|
115
115
|
|
|
@@ -122,16 +122,16 @@ module RailsConsoleAI
|
|
|
122
122
|
return nil
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
RailsConsoleAi::SessionLogger.update(session.id, name: new_name)
|
|
126
126
|
$stdout.puts "\e[36mSession ##{session.id} named: #{new_name}\e[0m"
|
|
127
127
|
nil
|
|
128
128
|
rescue => e
|
|
129
|
-
$stderr.puts "\e[
|
|
129
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
130
130
|
nil
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
def ai_setup
|
|
134
|
-
|
|
134
|
+
RailsConsoleAi.setup!
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
def ai_init
|
|
@@ -143,7 +143,7 @@ module RailsConsoleAI
|
|
|
143
143
|
repl = Repl.new(__rails_console_ai_binding)
|
|
144
144
|
repl.init_guide
|
|
145
145
|
rescue => e
|
|
146
|
-
$stderr.puts "\e[
|
|
146
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
147
147
|
nil
|
|
148
148
|
end
|
|
149
149
|
|
|
@@ -173,7 +173,7 @@ module RailsConsoleAI
|
|
|
173
173
|
repl = Repl.new(__rails_console_ai_binding)
|
|
174
174
|
repl.one_shot(query.to_s)
|
|
175
175
|
rescue => e
|
|
176
|
-
$stderr.puts "\e[
|
|
176
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
177
177
|
nil
|
|
178
178
|
end
|
|
179
179
|
|
|
@@ -193,7 +193,7 @@ module RailsConsoleAI
|
|
|
193
193
|
repl.interactive
|
|
194
194
|
end
|
|
195
195
|
rescue => e
|
|
196
|
-
$stderr.puts "\e[
|
|
196
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
197
197
|
nil
|
|
198
198
|
end
|
|
199
199
|
|
|
@@ -213,14 +213,14 @@ module RailsConsoleAI
|
|
|
213
213
|
repl = Repl.new(__rails_console_ai_binding)
|
|
214
214
|
repl.explain(query.to_s)
|
|
215
215
|
rescue => e
|
|
216
|
-
$stderr.puts "\e[
|
|
216
|
+
$stderr.puts "\e[31mRailsConsoleAi error: #{e.message}\e[0m"
|
|
217
217
|
nil
|
|
218
218
|
end
|
|
219
219
|
|
|
220
220
|
private
|
|
221
221
|
|
|
222
222
|
def __find_session(identifier)
|
|
223
|
-
session_class = Object.const_get('
|
|
223
|
+
session_class = Object.const_get('RailsConsoleAi::Session')
|
|
224
224
|
if identifier.is_a?(Integer)
|
|
225
225
|
session_class.find_by(id: identifier)
|
|
226
226
|
else
|
|
@@ -246,11 +246,11 @@ module RailsConsoleAI
|
|
|
246
246
|
end
|
|
247
247
|
|
|
248
248
|
def __ensure_rails_console_ai_user
|
|
249
|
-
return if
|
|
250
|
-
$stdout.puts "\e[
|
|
249
|
+
return if RailsConsoleAi.current_user
|
|
250
|
+
$stdout.puts "\e[36mRailsConsoleAi logs all AI sessions for audit purposes.\e[0m"
|
|
251
251
|
$stdout.print "\e[36mPlease enter your name: \e[0m"
|
|
252
252
|
name = $stdin.gets.to_s.strip
|
|
253
|
-
|
|
253
|
+
RailsConsoleAi.current_user = name.empty? ? ENV['USER'] : name
|
|
254
254
|
end
|
|
255
255
|
|
|
256
256
|
def __rails_console_ai_binding
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
module
|
|
1
|
+
module RailsConsoleAi
|
|
2
2
|
class ContextBuilder
|
|
3
|
-
def initialize(config =
|
|
3
|
+
def initialize(config = RailsConsoleAi.configuration)
|
|
4
4
|
@config = config
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def build
|
|
8
8
|
build_smart
|
|
9
9
|
rescue => e
|
|
10
|
-
|
|
10
|
+
RailsConsoleAi.logger.warn("RailsConsoleAi: context build error: #{e.message}")
|
|
11
11
|
smart_system_instructions + "\n\n" + environment_context
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -90,12 +90,12 @@ module RailsConsoleAI
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
def guide_context
|
|
93
|
-
content =
|
|
93
|
+
content = RailsConsoleAi.storage.read(RailsConsoleAi::GUIDE_KEY)
|
|
94
94
|
return nil if content.nil? || content.strip.empty?
|
|
95
95
|
|
|
96
96
|
"## Application Guide\n\n#{content.strip}"
|
|
97
97
|
rescue => e
|
|
98
|
-
|
|
98
|
+
RailsConsoleAi.logger.debug("RailsConsoleAi: guide context failed: #{e.message}")
|
|
99
99
|
nil
|
|
100
100
|
end
|
|
101
101
|
|
|
@@ -112,7 +112,7 @@ module RailsConsoleAI
|
|
|
112
112
|
lines << "Call recall_memories to get details before answering. Do NOT guess from the name alone."
|
|
113
113
|
lines.join("\n")
|
|
114
114
|
rescue => e
|
|
115
|
-
|
|
115
|
+
RailsConsoleAi.logger.debug("RailsConsoleAi: memory context failed: #{e.message}")
|
|
116
116
|
nil
|
|
117
117
|
end
|
|
118
118
|
|