rails_console_ai 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +95 -0
  3. data/LICENSE +21 -0
  4. data/README.md +328 -0
  5. data/app/controllers/rails_console_ai/application_controller.rb +28 -0
  6. data/app/controllers/rails_console_ai/sessions_controller.rb +16 -0
  7. data/app/helpers/rails_console_ai/sessions_helper.rb +56 -0
  8. data/app/models/rails_console_ai/session.rb +23 -0
  9. data/app/views/layouts/rails_console_ai/application.html.erb +84 -0
  10. data/app/views/rails_console_ai/sessions/index.html.erb +57 -0
  11. data/app/views/rails_console_ai/sessions/show.html.erb +66 -0
  12. data/config/routes.rb +4 -0
  13. data/lib/generators/rails_console_ai/install_generator.rb +26 -0
  14. data/lib/generators/rails_console_ai/templates/initializer.rb +79 -0
  15. data/lib/rails_console_ai/channel/base.rb +23 -0
  16. data/lib/rails_console_ai/channel/console.rb +457 -0
  17. data/lib/rails_console_ai/channel/slack.rb +182 -0
  18. data/lib/rails_console_ai/configuration.rb +185 -0
  19. data/lib/rails_console_ai/console_methods.rb +277 -0
  20. data/lib/rails_console_ai/context_builder.rb +120 -0
  21. data/lib/rails_console_ai/conversation_engine.rb +1142 -0
  22. data/lib/rails_console_ai/engine.rb +5 -0
  23. data/lib/rails_console_ai/executor.rb +461 -0
  24. data/lib/rails_console_ai/providers/anthropic.rb +122 -0
  25. data/lib/rails_console_ai/providers/base.rb +118 -0
  26. data/lib/rails_console_ai/providers/bedrock.rb +171 -0
  27. data/lib/rails_console_ai/providers/local.rb +112 -0
  28. data/lib/rails_console_ai/providers/openai.rb +114 -0
  29. data/lib/rails_console_ai/railtie.rb +34 -0
  30. data/lib/rails_console_ai/repl.rb +65 -0
  31. data/lib/rails_console_ai/safety_guards.rb +207 -0
  32. data/lib/rails_console_ai/session_logger.rb +90 -0
  33. data/lib/rails_console_ai/slack_bot.rb +473 -0
  34. data/lib/rails_console_ai/storage/base.rb +27 -0
  35. data/lib/rails_console_ai/storage/file_storage.rb +63 -0
  36. data/lib/rails_console_ai/tools/code_tools.rb +126 -0
  37. data/lib/rails_console_ai/tools/memory_tools.rb +136 -0
  38. data/lib/rails_console_ai/tools/model_tools.rb +95 -0
  39. data/lib/rails_console_ai/tools/registry.rb +478 -0
  40. data/lib/rails_console_ai/tools/schema_tools.rb +60 -0
  41. data/lib/rails_console_ai/version.rb +3 -0
  42. data/lib/rails_console_ai.rb +214 -0
  43. data/lib/tasks/rails_console_ai.rake +7 -0
  44. metadata +152 -0
@@ -0,0 +1,57 @@
1
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
2
+ <h2 style="font-size: 20px;">Sessions</h2>
3
+ <span class="text-muted" style="font-size: 14px;"><%= @total %> total</span>
4
+ </div>
5
+
6
+ <% if @sessions.empty? %>
7
+ <div class="meta-card">
8
+ <p class="text-muted">No sessions recorded yet.</p>
9
+ </div>
10
+ <% else %>
11
+ <table>
12
+ <thead>
13
+ <tr>
14
+ <th>Time</th>
15
+ <th>User</th>
16
+ <th>Name</th>
17
+ <th style="max-width: 400px;">Query</th>
18
+ <th>Mode</th>
19
+ <th>Tokens</th>
20
+ <th>Cost</th>
21
+ <th>Duration</th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <% @sessions.each do |session| %>
26
+ <tr>
27
+ <td class="mono"><%= session.created_at.strftime('%Y-%m-%d %H:%M') %></td>
28
+ <td><%= session.user_name %></td>
29
+ <td><%= session.name.present? ? session.name : '-' %></td>
30
+ <td class="query-cell"><a href="<%= rails_console_ai.session_path(session) %>" title="<%= h session.query.truncate(200) %>"><%= truncate(session.query.gsub(/\s+/, ' ').strip, length: 80) %></a></td>
31
+ <td><span class="badge badge-<%= session.mode %>"><%= session.mode %></span></td>
32
+ <td class="mono"><%= session.input_tokens + session.output_tokens %></td>
33
+ <td class="mono"><%= format_cost(session) %></td>
34
+ <td class="mono"><%= session.duration_ms ? "#{session.duration_ms}ms" : '-' %></td>
35
+ </tr>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
39
+
40
+ <% if @total_pages > 1 %>
41
+ <div class="pagination">
42
+ <% if @page > 1 %>
43
+ <a href="<%= rails_console_ai.sessions_path(page: @page - 1) %>">&larr; Newer</a>
44
+ <% else %>
45
+ <span class="disabled">&larr; Newer</span>
46
+ <% end %>
47
+
48
+ <span class="page-info">Page <%= @page %> of <%= @total_pages %></span>
49
+
50
+ <% if @page < @total_pages %>
51
+ <a href="<%= rails_console_ai.sessions_path(page: @page + 1) %>">Older &rarr;</a>
52
+ <% else %>
53
+ <span class="disabled">Older &rarr;</span>
54
+ <% end %>
55
+ </div>
56
+ <% end %>
57
+ <% end %>
@@ -0,0 +1,66 @@
1
+ <a href="<%= rails_console_ai.sessions_path %>" class="back-link">&larr; Back to sessions</a>
2
+
3
+ <div class="meta-card">
4
+ <div class="meta-grid">
5
+ <div class="meta-item" style="grid-column: 1 / -1;">
6
+ <label>Query</label>
7
+ <% if @session.query.length > 300 %>
8
+ <div class="query-preview">
9
+ <span><%= truncate(@session.query, length: 300) %></span>
10
+ <details style="margin-top: 4px;">
11
+ <summary style="cursor: pointer; font-size: 12px; color: #4a6fa5;">Show full query</summary>
12
+ <pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 13px; margin-top: 8px; padding: 12px; background: #f8f9fa; border-radius: 4px; max-height: 400px; overflow-y: auto;"><%= @session.query %></pre>
13
+ </details>
14
+ </div>
15
+ <% else %>
16
+ <span><%= @session.query %></span>
17
+ <% end %>
18
+ </div>
19
+ <% if @session.name.present? %>
20
+ <div class="meta-item">
21
+ <label>Name</label>
22
+ <span><%= @session.name %></span>
23
+ </div>
24
+ <% end %>
25
+ <div class="meta-item">
26
+ <label>Mode</label>
27
+ <span class="badge badge-<%= @session.mode %>"><%= @session.mode %></span>
28
+ </div>
29
+ <div class="meta-item">
30
+ <label>User</label>
31
+ <span><%= @session.user_name || '-' %></span>
32
+ </div>
33
+ <div class="meta-item">
34
+ <label>Provider / Model</label>
35
+ <span><%= @session.provider %> / <%= @session.model %></span>
36
+ </div>
37
+ <div class="meta-item">
38
+ <label>Tokens (in / out)</label>
39
+ <span class="mono"><%= @session.input_tokens %> / <%= @session.output_tokens %></span>
40
+ </div>
41
+ <div class="meta-item">
42
+ <label>Est. Cost</label>
43
+ <span class="mono"><%= format_cost(@session) %></span>
44
+ </div>
45
+ <div class="meta-item">
46
+ <label>Duration</label>
47
+ <span class="mono"><%= @session.duration_ms ? "#{@session.duration_ms}ms" : '-' %></span>
48
+ </div>
49
+ <div class="meta-item">
50
+ <label>Time</label>
51
+ <span><%= @session.created_at.strftime('%Y-%m-%d %H:%M:%S') %></span>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <h3 style="font-size: 16px; margin-bottom: 12px;">Console Output</h3>
57
+
58
+ <% if @session.console_output.present? %>
59
+ <div class="terminal">
60
+ <pre><%= ansi_to_html(@session.console_output) %></pre>
61
+ </div>
62
+ <% else %>
63
+ <div class="meta-card">
64
+ <p class="text-muted">No console output recorded for this session.</p>
65
+ </div>
66
+ <% end %>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ RailsConsoleAI::Engine.routes.draw do
2
+ root to: 'sessions#index'
3
+ resources :sessions, only: [:index, :show]
4
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails/generators'
2
+
3
+ module RailsConsoleAI
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+ desc 'Creates a RailsConsoleAI initializer in config/initializers/'
8
+
9
+ def copy_initializer
10
+ template 'initializer.rb', 'config/initializers/rails_console_ai.rb'
11
+ end
12
+
13
+ def show_readme
14
+ say ''
15
+ say 'RailsConsoleAI installed!', :green
16
+ say ''
17
+ say 'Next steps:'
18
+ say ' 1. Set your API key: export ANTHROPIC_API_KEY=sk-...'
19
+ say ' 2. Edit config/initializers/rails_console_ai.rb if needed'
20
+ say ' 3. Run: rails console'
21
+ say ' 4. Try: ai "show me all tables"'
22
+ say ''
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,79 @@
1
+ RailsConsoleAI.configure do |config|
2
+ # LLM provider: :anthropic, :openai, or :local
3
+ config.provider = :anthropic
4
+
5
+ # API key (or set ANTHROPIC_API_KEY / OPENAI_API_KEY env var)
6
+ # config.api_key = 'sk-...'
7
+
8
+ # Model override (defaults: claude-opus-4-6 for Anthropic, gpt-5.3-codex for OpenAI)
9
+ # config.model = 'claude-opus-4-6'
10
+
11
+ # Max tokens for LLM response
12
+ config.max_tokens = 4096
13
+
14
+ # Temperature (0.0 - 1.0)
15
+ config.temperature = 0.2
16
+
17
+ # Auto-execute generated code without confirmation (use with caution!)
18
+ config.auto_execute = false
19
+
20
+ # Max tool-use rounds per query (safety cap)
21
+ config.max_tool_rounds = 10
22
+
23
+ # HTTP timeout in seconds
24
+ config.timeout = 30
25
+
26
+ # Local model provider (Ollama, vLLM, or any OpenAI-compatible server):
27
+ # config.provider = :local
28
+ # config.local_url = 'http://localhost:11434'
29
+ # config.local_model = 'qwen2.5:7b'
30
+ # config.local_api_key = nil
31
+
32
+ # Slack: which users the bot responds to (required for Slack mode)
33
+ # config.slack_allowed_usernames = ['alice', 'bob'] # specific users
34
+ # config.slack_allowed_usernames = 'ALL' # everyone
35
+
36
+ # AWS Bedrock provider (uses AWS credential chain — no API key needed):
37
+ # config.provider = :bedrock
38
+ # config.bedrock_region = 'us-east-1'
39
+ # config.model = 'us.anthropic.claude-sonnet-4-6'
40
+
41
+ # Debug mode: prints full API requests/responses and tool calls to stderr
42
+ # config.debug = true
43
+
44
+ # Session logging: persist AI sessions to the database
45
+ # Run RailsConsoleAI.setup! in the Rails console to create the table
46
+ config.session_logging = true
47
+
48
+ # Database connection for RailsConsoleAI tables (default: ActiveRecord::Base)
49
+ # Set to a class that responds to .connection if tables live on a different DB
50
+ # config.connection_class = Sharding::CentralizedModel
51
+
52
+ # Admin UI credentials (mount RailsConsoleAI::Engine => '/rails_console_ai' in routes.rb)
53
+ # When nil, all requests are denied. Set credentials or use config.authenticate.
54
+ # config.admin_username = 'admin'
55
+ # config.admin_password = 'changeme'
56
+
57
+ # Safety guards: prevent side effects (DB writes, HTTP calls, etc.) during code execution.
58
+ # When enabled, code runs in safe mode by default. Users can toggle with /danger in the REPL.
59
+ #
60
+ # Built-in guard for database writes (works on Rails 5+, all adapters):
61
+ # config.use_builtin_safety_guard :database_writes
62
+ #
63
+ # Built-in guard for HTTP mutations — blocks POST/PUT/PATCH/DELETE via Net::HTTP.
64
+ # Covers most Ruby HTTP libraries (HTTParty, RestClient, Faraday) since they use Net::HTTP:
65
+ # config.use_builtin_safety_guard :http_mutations
66
+ #
67
+ # Allowlist specific hosts or tables so they pass through without blocking:
68
+ # config.use_builtin_safety_guard :http_mutations,
69
+ # allow: [/s3\.amazonaws\.com/, /googleapis\.com/]
70
+ # config.use_builtin_safety_guard :database_writes,
71
+ # allow: ['rails_console_ai_sessions']
72
+ #
73
+ # Built-in guard for mailers — disables ActionMailer delivery:
74
+ # config.use_builtin_safety_guard :mailers
75
+ #
76
+ # config.safety_guard :jobs do |&execute|
77
+ # Sidekiq::Testing.fake! { execute.call }
78
+ # end
79
+ end
@@ -0,0 +1,23 @@
1
+ module RailsConsoleAI
2
+ module Channel
3
+ class Base
4
+ def display(text); raise NotImplementedError; end
5
+ def display_dim(text); raise NotImplementedError; end
6
+ def display_warning(text); raise NotImplementedError; end
7
+ def display_error(text); raise NotImplementedError; end
8
+ def display_code(code); raise NotImplementedError; end
9
+ def display_result(text); raise NotImplementedError; end
10
+ def display_result_output(text); end # stdout output from code execution
11
+ def prompt(text); raise NotImplementedError; end
12
+ def confirm(text); raise NotImplementedError; end
13
+ def user_identity; raise NotImplementedError; end
14
+ def mode; raise NotImplementedError; end
15
+ def cancelled?; false; end
16
+ def supports_danger?; true; end
17
+ def supports_editing?; false; end
18
+ def edit_code(code); code; end
19
+ def wrap_llm_call(&block); yield; end
20
+ def system_instructions; nil; end
21
+ end
22
+ end
23
+ end