rails_console_ai 0.30.0 → 0.32.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 +14 -26
- data/README.md +33 -11
- data/app/controllers/rails_console_ai/agent_versions_controller.rb +2 -9
- data/app/controllers/rails_console_ai/agents_controller.rb +25 -48
- data/app/controllers/rails_console_ai/memories_controller.rb +35 -38
- data/app/controllers/rails_console_ai/memory_versions_controller.rb +2 -6
- data/app/controllers/rails_console_ai/sessions_controller.rb +1 -1
- data/app/controllers/rails_console_ai/skill_versions_controller.rb +2 -8
- data/app/controllers/rails_console_ai/skills_controller.rb +19 -48
- data/app/models/rails_console_ai/agent.rb +33 -65
- data/app/models/rails_console_ai/agent_version.rb +8 -20
- data/app/models/rails_console_ai/memory.rb +67 -23
- data/app/models/rails_console_ai/memory_version.rb +5 -20
- data/app/models/rails_console_ai/skill.rb +55 -105
- data/app/models/rails_console_ai/skill_version.rb +7 -28
- data/app/views/rails_console_ai/agents/_form.html.erb +9 -34
- data/app/views/rails_console_ai/agents/diff.html.erb +1 -5
- data/app/views/rails_console_ai/agents/new.html.erb +0 -16
- data/app/views/rails_console_ai/memories/_form.html.erb +6 -13
- data/app/views/rails_console_ai/memories/diff.html.erb +1 -5
- data/app/views/rails_console_ai/memories/index.html.erb +13 -1
- data/app/views/rails_console_ai/memories/new.html.erb +0 -15
- data/app/views/rails_console_ai/memories/show.html.erb +23 -0
- data/app/views/rails_console_ai/skills/_form.html.erb +7 -29
- data/app/views/rails_console_ai/skills/diff.html.erb +1 -8
- data/app/views/rails_console_ai/skills/new.html.erb +0 -17
- data/config/routes.rb +3 -3
- data/lib/generators/rails_console_ai/templates/initializer.rb +5 -5
- data/lib/rails_console_ai/agent_loader.rb +18 -10
- data/lib/rails_console_ai/agent_runner.rb +66 -4
- data/lib/rails_console_ai/channel/console.rb +1 -1
- data/lib/rails_console_ai/configuration.rb +51 -33
- data/lib/rails_console_ai/conversation_engine.rb +3 -3
- data/lib/rails_console_ai/safety_guards.rb +36 -0
- data/lib/rails_console_ai/session_logger.rb +4 -0
- data/lib/rails_console_ai/skill_loader.rb +18 -9
- data/lib/rails_console_ai/slack_bot.rb +2 -2
- data/lib/rails_console_ai/storage/database_storage.rb +14 -20
- data/lib/rails_console_ai/sub_agent.rb +1 -1
- data/lib/rails_console_ai/tools/memory_tools.rb +37 -6
- data/lib/rails_console_ai/tools/registry.rb +18 -6
- data/lib/rails_console_ai/version.rb +1 -1
- data/lib/rails_console_ai.rb +92 -71
- metadata +1 -1
data/lib/rails_console_ai.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
1
3
|
require 'rails_console_ai/version'
|
|
2
4
|
require 'rails_console_ai/configuration'
|
|
3
5
|
|
|
@@ -57,8 +59,17 @@ module RailsConsoleAi
|
|
|
57
59
|
|
|
58
60
|
# Enqueue an agent run. Returns the Integer session id immediately;
|
|
59
61
|
# the actual work is picked up by `rake rails_console_ai:agents`.
|
|
60
|
-
|
|
62
|
+
#
|
|
63
|
+
# use_thinking_model: run on the configured thinking-tier model
|
|
64
|
+
# max_wall_clock_seconds: hard kill the run after N seconds (nil = no cap)
|
|
65
|
+
def run_agent(query, name: nil, user_name: nil,
|
|
66
|
+
use_thinking_model: false,
|
|
67
|
+
max_wall_clock_seconds: 600)
|
|
61
68
|
require 'rails_console_ai/session_logger'
|
|
69
|
+
options = {
|
|
70
|
+
'use_thinking_model' => !!use_thinking_model,
|
|
71
|
+
'max_wall_clock_seconds' => max_wall_clock_seconds
|
|
72
|
+
}
|
|
62
73
|
id = SessionLogger.log(
|
|
63
74
|
query: query,
|
|
64
75
|
conversation: [],
|
|
@@ -66,7 +77,8 @@ module RailsConsoleAi
|
|
|
66
77
|
name: name,
|
|
67
78
|
user_name: user_name,
|
|
68
79
|
status: 'queued',
|
|
69
|
-
executed: false
|
|
80
|
+
executed: false,
|
|
81
|
+
options: options
|
|
70
82
|
)
|
|
71
83
|
raise 'Failed to enqueue agent run (session logging disabled or table missing)' unless id
|
|
72
84
|
id
|
|
@@ -74,7 +86,7 @@ module RailsConsoleAi
|
|
|
74
86
|
|
|
75
87
|
# Returns the current status string for an enqueued agent run, or nil
|
|
76
88
|
# if the session id is not found. Status is one of:
|
|
77
|
-
# 'queued' | 'running' | 'ready' | 'failed'.
|
|
89
|
+
# 'queued' | 'running' | 'ready' | 'failed' | 'aborted'.
|
|
78
90
|
def check_agent(session_id)
|
|
79
91
|
Session.where(id: session_id).pluck(:status).first
|
|
80
92
|
end
|
|
@@ -88,6 +100,16 @@ module RailsConsoleAi
|
|
|
88
100
|
{ status: row.status, result: row.result, error: row.error_message }
|
|
89
101
|
end
|
|
90
102
|
|
|
103
|
+
# Abort a queued or running agent run. Returns true if the run was
|
|
104
|
+
# aborted, false if it had already finished (or doesn't exist).
|
|
105
|
+
# Queued runs are never picked up; a run already executing keeps
|
|
106
|
+
# going but its result is discarded when it completes.
|
|
107
|
+
def abort_agent(session_id)
|
|
108
|
+
n = Session.where(id: session_id, status: %w[queued running])
|
|
109
|
+
.update_all(status: 'aborted', error_message: 'Aborted')
|
|
110
|
+
n == 1
|
|
111
|
+
end
|
|
112
|
+
|
|
91
113
|
def status
|
|
92
114
|
c = configuration
|
|
93
115
|
key = c.resolved_api_key
|
|
@@ -145,6 +167,7 @@ module RailsConsoleAi
|
|
|
145
167
|
t.string :slack_thread_ts, limit: 255
|
|
146
168
|
t.string :slack_channel_name, limit: 255
|
|
147
169
|
t.integer :duration_ms
|
|
170
|
+
t.text :options
|
|
148
171
|
t.datetime :created_at, null: false
|
|
149
172
|
end
|
|
150
173
|
|
|
@@ -169,13 +192,22 @@ module RailsConsoleAi
|
|
|
169
192
|
skills_table = 'rails_console_ai_skills'
|
|
170
193
|
versions_table = 'rails_console_ai_skill_versions'
|
|
171
194
|
|
|
195
|
+
# Old shape had per-field columns (body, tags, bypass_guards_for_methods,
|
|
196
|
+
# description). New shape stores the raw .md in `content`. Pre-production,
|
|
197
|
+
# so we drop and recreate when the old shape is detected.
|
|
198
|
+
if conn.table_exists?(skills_table) && !conn.column_exists?(skills_table, :content)
|
|
199
|
+
conn.drop_table(skills_table)
|
|
200
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{skills_table} (replaced with single-content schema).\e[0m"
|
|
201
|
+
end
|
|
202
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :content)
|
|
203
|
+
conn.drop_table(versions_table)
|
|
204
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{versions_table}.\e[0m"
|
|
205
|
+
end
|
|
206
|
+
|
|
172
207
|
unless conn.table_exists?(skills_table)
|
|
173
208
|
conn.create_table(skills_table) do |t|
|
|
174
209
|
t.string :name, limit: 255, null: false
|
|
175
|
-
t.text :
|
|
176
|
-
t.text :body
|
|
177
|
-
t.text :tags
|
|
178
|
-
t.text :bypass_guards_for_methods
|
|
210
|
+
t.text :content, null: false
|
|
179
211
|
t.string :status, limit: 20, default: 'proposed', null: false
|
|
180
212
|
t.string :approved_by, limit: 255
|
|
181
213
|
t.datetime :approved_at
|
|
@@ -187,34 +219,13 @@ module RailsConsoleAi
|
|
|
187
219
|
conn.add_index(skills_table, :name, unique: true)
|
|
188
220
|
conn.add_index(skills_table, :status)
|
|
189
221
|
$stdout.puts "\e[32mRailsConsoleAi: created #{skills_table} table.\e[0m"
|
|
190
|
-
else
|
|
191
|
-
# Idempotent column-add probes for existing installs.
|
|
192
|
-
unless conn.column_exists?(skills_table, :status)
|
|
193
|
-
conn.add_column(skills_table, :status, :string, limit: 20, default: 'proposed', null: false)
|
|
194
|
-
conn.add_index(skills_table, :status) unless conn.index_exists?(skills_table, :status)
|
|
195
|
-
end
|
|
196
|
-
unless conn.column_exists?(skills_table, :approved_by)
|
|
197
|
-
conn.add_column(skills_table, :approved_by, :string, limit: 255)
|
|
198
|
-
end
|
|
199
|
-
unless conn.column_exists?(skills_table, :approved_at)
|
|
200
|
-
conn.add_column(skills_table, :approved_at, :datetime)
|
|
201
|
-
end
|
|
202
|
-
unless conn.column_exists?(skills_table, :use_count)
|
|
203
|
-
conn.add_column(skills_table, :use_count, :integer, default: 0, null: false)
|
|
204
|
-
end
|
|
205
|
-
unless conn.column_exists?(skills_table, :last_used_at)
|
|
206
|
-
conn.add_column(skills_table, :last_used_at, :datetime)
|
|
207
|
-
end
|
|
208
222
|
end
|
|
209
223
|
|
|
210
224
|
unless conn.table_exists?(versions_table)
|
|
211
225
|
conn.create_table(versions_table) do |t|
|
|
212
226
|
t.integer :skill_id
|
|
213
227
|
t.string :name, limit: 255
|
|
214
|
-
t.text :
|
|
215
|
-
t.text :body
|
|
216
|
-
t.text :tags
|
|
217
|
-
t.text :bypass_guards_for_methods
|
|
228
|
+
t.text :content
|
|
218
229
|
t.string :status, limit: 20
|
|
219
230
|
t.string :edited_by, limit: 255
|
|
220
231
|
t.text :change_note
|
|
@@ -223,10 +234,6 @@ module RailsConsoleAi
|
|
|
223
234
|
conn.add_index(versions_table, :skill_id)
|
|
224
235
|
conn.add_index(versions_table, :created_at)
|
|
225
236
|
$stdout.puts "\e[32mRailsConsoleAi: created #{versions_table} table.\e[0m"
|
|
226
|
-
else
|
|
227
|
-
unless conn.column_exists?(versions_table, :status)
|
|
228
|
-
conn.add_column(versions_table, :status, :string, limit: 20)
|
|
229
|
-
end
|
|
230
237
|
end
|
|
231
238
|
end
|
|
232
239
|
|
|
@@ -234,33 +241,54 @@ module RailsConsoleAi
|
|
|
234
241
|
memories_table = 'rails_console_ai_memories'
|
|
235
242
|
versions_table = 'rails_console_ai_memory_versions'
|
|
236
243
|
|
|
244
|
+
if conn.table_exists?(memories_table) && !conn.column_exists?(memories_table, :content)
|
|
245
|
+
conn.drop_table(memories_table)
|
|
246
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{memories_table}.\e[0m"
|
|
247
|
+
end
|
|
248
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :content)
|
|
249
|
+
conn.drop_table(versions_table)
|
|
250
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{versions_table}.\e[0m"
|
|
251
|
+
end
|
|
252
|
+
|
|
237
253
|
unless conn.table_exists?(memories_table)
|
|
238
254
|
conn.create_table(memories_table) do |t|
|
|
239
255
|
t.string :name, limit: 255, null: false
|
|
240
|
-
t.text :
|
|
241
|
-
t.
|
|
256
|
+
t.text :content, null: false
|
|
257
|
+
t.string :status, limit: 20, default: 'proposed', null: false
|
|
258
|
+
t.string :approved_by, limit: 255
|
|
259
|
+
t.datetime :approved_at
|
|
242
260
|
t.integer :use_count, default: 0, null: false
|
|
243
261
|
t.datetime :last_used_at
|
|
244
262
|
t.datetime :created_at, null: false
|
|
245
263
|
t.datetime :updated_at, null: false
|
|
246
264
|
end
|
|
247
265
|
conn.add_index(memories_table, :name, unique: true)
|
|
266
|
+
conn.add_index(memories_table, :status)
|
|
248
267
|
$stdout.puts "\e[32mRailsConsoleAi: created #{memories_table} table.\e[0m"
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Existing installs have the content-based memories table but predate the
|
|
271
|
+
# approval columns — the drop-on-missing-content guard above won't fire for
|
|
272
|
+
# them, so add the columns in place. Memories created before approval existed
|
|
273
|
+
# were trusted under the old no-approval regime, so grandfather them to
|
|
274
|
+
# "approved" rather than yanking them out from under the AI; only memories
|
|
275
|
+
# created from now on start in "proposed".
|
|
276
|
+
if conn.table_exists?(memories_table) && !conn.column_exists?(memories_table, :status)
|
|
277
|
+
conn.add_column(memories_table, :status, :string, limit: 20, default: 'proposed', null: false)
|
|
278
|
+
conn.execute("UPDATE #{conn.quote_table_name(memories_table)} SET status = 'approved'")
|
|
279
|
+
end
|
|
280
|
+
if conn.table_exists?(memories_table)
|
|
281
|
+
conn.add_column(memories_table, :approved_by, :string, limit: 255) unless conn.column_exists?(memories_table, :approved_by)
|
|
282
|
+
conn.add_column(memories_table, :approved_at, :datetime) unless conn.column_exists?(memories_table, :approved_at)
|
|
283
|
+
conn.add_index(memories_table, :status) unless conn.index_exists?(memories_table, :status)
|
|
256
284
|
end
|
|
257
285
|
|
|
258
286
|
unless conn.table_exists?(versions_table)
|
|
259
287
|
conn.create_table(versions_table) do |t|
|
|
260
288
|
t.integer :memory_id
|
|
261
289
|
t.string :name, limit: 255
|
|
262
|
-
t.text :
|
|
263
|
-
t.
|
|
290
|
+
t.text :content
|
|
291
|
+
t.string :status, limit: 20
|
|
264
292
|
t.string :edited_by, limit: 255
|
|
265
293
|
t.text :change_note
|
|
266
294
|
t.datetime :created_at, null: false
|
|
@@ -269,20 +297,29 @@ module RailsConsoleAi
|
|
|
269
297
|
conn.add_index(versions_table, :created_at)
|
|
270
298
|
$stdout.puts "\e[32mRailsConsoleAi: created #{versions_table} table.\e[0m"
|
|
271
299
|
end
|
|
300
|
+
|
|
301
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :status)
|
|
302
|
+
conn.add_column(versions_table, :status, :string, limit: 20)
|
|
303
|
+
end
|
|
272
304
|
end
|
|
273
305
|
|
|
274
306
|
def setup_agents_tables!(conn)
|
|
275
307
|
agents_table = 'rails_console_ai_agents'
|
|
276
308
|
versions_table = 'rails_console_ai_agent_versions'
|
|
277
309
|
|
|
310
|
+
if conn.table_exists?(agents_table) && !conn.column_exists?(agents_table, :content)
|
|
311
|
+
conn.drop_table(agents_table)
|
|
312
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{agents_table}.\e[0m"
|
|
313
|
+
end
|
|
314
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :content)
|
|
315
|
+
conn.drop_table(versions_table)
|
|
316
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{versions_table}.\e[0m"
|
|
317
|
+
end
|
|
318
|
+
|
|
278
319
|
unless conn.table_exists?(agents_table)
|
|
279
320
|
conn.create_table(agents_table) do |t|
|
|
280
321
|
t.string :name, limit: 255, null: false
|
|
281
|
-
t.text :
|
|
282
|
-
t.text :body
|
|
283
|
-
t.integer :max_rounds
|
|
284
|
-
t.string :model, limit: 100
|
|
285
|
-
t.text :tools
|
|
322
|
+
t.text :content, null: false
|
|
286
323
|
t.string :status, limit: 20, default: 'proposed', null: false
|
|
287
324
|
t.string :approved_by, limit: 255
|
|
288
325
|
t.datetime :approved_at
|
|
@@ -294,34 +331,13 @@ module RailsConsoleAi
|
|
|
294
331
|
conn.add_index(agents_table, :name, unique: true)
|
|
295
332
|
conn.add_index(agents_table, :status)
|
|
296
333
|
$stdout.puts "\e[32mRailsConsoleAi: created #{agents_table} table.\e[0m"
|
|
297
|
-
else
|
|
298
|
-
unless conn.column_exists?(agents_table, :status)
|
|
299
|
-
conn.add_column(agents_table, :status, :string, limit: 20, default: 'proposed', null: false)
|
|
300
|
-
conn.add_index(agents_table, :status) unless conn.index_exists?(agents_table, :status)
|
|
301
|
-
end
|
|
302
|
-
unless conn.column_exists?(agents_table, :approved_by)
|
|
303
|
-
conn.add_column(agents_table, :approved_by, :string, limit: 255)
|
|
304
|
-
end
|
|
305
|
-
unless conn.column_exists?(agents_table, :approved_at)
|
|
306
|
-
conn.add_column(agents_table, :approved_at, :datetime)
|
|
307
|
-
end
|
|
308
|
-
unless conn.column_exists?(agents_table, :use_count)
|
|
309
|
-
conn.add_column(agents_table, :use_count, :integer, default: 0, null: false)
|
|
310
|
-
end
|
|
311
|
-
unless conn.column_exists?(agents_table, :last_used_at)
|
|
312
|
-
conn.add_column(agents_table, :last_used_at, :datetime)
|
|
313
|
-
end
|
|
314
334
|
end
|
|
315
335
|
|
|
316
336
|
unless conn.table_exists?(versions_table)
|
|
317
337
|
conn.create_table(versions_table) do |t|
|
|
318
338
|
t.integer :agent_id
|
|
319
339
|
t.string :name, limit: 255
|
|
320
|
-
t.text :
|
|
321
|
-
t.text :body
|
|
322
|
-
t.integer :max_rounds
|
|
323
|
-
t.string :model, limit: 100
|
|
324
|
-
t.text :tools
|
|
340
|
+
t.text :content
|
|
325
341
|
t.string :status, limit: 20
|
|
326
342
|
t.string :edited_by, limit: 255
|
|
327
343
|
t.text :change_note
|
|
@@ -376,6 +392,11 @@ module RailsConsoleAi
|
|
|
376
392
|
migrations << 'error_message'
|
|
377
393
|
end
|
|
378
394
|
|
|
395
|
+
unless conn.column_exists?(table, :options)
|
|
396
|
+
conn.add_column(table, :options, :text)
|
|
397
|
+
migrations << 'options'
|
|
398
|
+
end
|
|
399
|
+
|
|
379
400
|
unless conn.index_exists?(table, [:mode, :status], name: 'idx_rca_sessions_mode_status')
|
|
380
401
|
conn.add_index(table, [:mode, :status], name: 'idx_rca_sessions_mode_status')
|
|
381
402
|
migrations << 'idx_rca_sessions_mode_status'
|