rails_console_ai 0.30.0 → 0.31.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 +6 -0
- data/README.md +18 -1
- data/app/controllers/rails_console_ai/agent_versions_controller.rb +1 -8
- data/app/controllers/rails_console_ai/agents_controller.rb +24 -47
- data/app/controllers/rails_console_ai/memories_controller.rb +13 -36
- data/app/controllers/rails_console_ai/memory_versions_controller.rb +1 -5
- data/app/controllers/rails_console_ai/skill_versions_controller.rb +1 -7
- data/app/controllers/rails_console_ai/skills_controller.rb +18 -47
- 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 +28 -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/new.html.erb +0 -15
- 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 +0 -3
- data/lib/rails_console_ai/agent_loader.rb +18 -10
- data/lib/rails_console_ai/agent_runner.rb +55 -4
- 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/storage/database_storage.rb +14 -20
- data/lib/rails_console_ai/tools/memory_tools.rb +8 -0
- data/lib/rails_console_ai/version.rb +1 -1
- data/lib/rails_console_ai.rb +54 -70
- metadata +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'json'
|
|
1
2
|
require 'rails_console_ai/prefixed_io'
|
|
2
3
|
require 'rails_console_ai/session_logger'
|
|
3
4
|
require 'rails_console_ai/channel/api'
|
|
@@ -7,6 +8,8 @@ require 'rails_console_ai/providers/base'
|
|
|
7
8
|
require 'rails_console_ai/executor'
|
|
8
9
|
|
|
9
10
|
module RailsConsoleAi
|
|
11
|
+
class RunnerTimeoutError < StandardError; end
|
|
12
|
+
|
|
10
13
|
# Long-running worker that polls the sessions table for queued agent_api
|
|
11
14
|
# rows, claims them atomically, and runs each in its own Thread via
|
|
12
15
|
# ConversationEngine#one_shot. Started by `rake rails_console_ai:agents`.
|
|
@@ -87,13 +90,20 @@ module RailsConsoleAi
|
|
|
87
90
|
|
|
88
91
|
def spawn(session)
|
|
89
92
|
tag = "[agent/#{session.id}] @#{session.user_name || '?'}"
|
|
90
|
-
|
|
93
|
+
opts = parse_options(session)
|
|
94
|
+
banner_extras = []
|
|
95
|
+
banner_extras << 'thinking' if opts['use_thinking_model']
|
|
96
|
+
if (cap = opts['max_wall_clock_seconds'])
|
|
97
|
+
banner_extras << "cap=#{cap}s"
|
|
98
|
+
end
|
|
99
|
+
banner = banner_extras.empty? ? '' : " (#{banner_extras.join(', ')})"
|
|
100
|
+
puts "#{tag}#{banner} << #{session.query.to_s.strip}"
|
|
91
101
|
|
|
92
102
|
t = Thread.new do
|
|
93
103
|
Thread.current.report_on_exception = false
|
|
94
104
|
Thread.current[:log_prefix] = tag
|
|
95
105
|
begin
|
|
96
|
-
run_one(session)
|
|
106
|
+
run_one(session, opts)
|
|
97
107
|
ensure
|
|
98
108
|
ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
|
|
99
109
|
end
|
|
@@ -101,13 +111,27 @@ module RailsConsoleAi
|
|
|
101
111
|
@mutex.synchronize { @threads[session.id] = t }
|
|
102
112
|
end
|
|
103
113
|
|
|
104
|
-
def
|
|
114
|
+
def parse_options(session)
|
|
115
|
+
raw = session.respond_to?(:options) ? session.options : nil
|
|
116
|
+
return {} if raw.nil? || raw.to_s.empty?
|
|
117
|
+
return raw if raw.is_a?(Hash)
|
|
118
|
+
JSON.parse(raw)
|
|
119
|
+
rescue => e
|
|
120
|
+
warn "AgentRunner: failed to parse session.options (#{e.class}: #{e.message}); ignoring."
|
|
121
|
+
{}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def run_one(session, opts = nil)
|
|
125
|
+
opts ||= parse_options(session)
|
|
105
126
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
106
127
|
channel = Channel::Api.new(user_name: session.user_name)
|
|
107
128
|
sandbox_binding = Object.new.instance_eval { binding }
|
|
108
129
|
engine = ConversationEngine.new(binding_context: sandbox_binding, channel: channel)
|
|
130
|
+
engine.upgrade_to_thinking_model if opts['use_thinking_model']
|
|
109
131
|
|
|
110
|
-
exec_result =
|
|
132
|
+
exec_result = run_with_deadline(opts['max_wall_clock_seconds']) do
|
|
133
|
+
engine.one_shot(session.query, existing_session_id: session.id)
|
|
134
|
+
end
|
|
111
135
|
result_text = compose_result(channel.captured_output, exec_result)
|
|
112
136
|
|
|
113
137
|
SessionLogger.update(session.id, status: 'ready', result: result_text)
|
|
@@ -116,6 +140,9 @@ module RailsConsoleAi
|
|
|
116
140
|
preview = result_text.to_s.strip.lines.first.to_s.strip
|
|
117
141
|
preview = preview[0, 120] + '…' if preview.length > 120
|
|
118
142
|
puts ">> ready (#{elapsed}ms) #{preview}"
|
|
143
|
+
rescue RunnerTimeoutError => e
|
|
144
|
+
warn ">> TIMEOUT #{e.message}"
|
|
145
|
+
SessionLogger.update(session.id, status: 'failed', error_message: e.message)
|
|
119
146
|
rescue => e
|
|
120
147
|
warn ">> FAILED #{e.class}: #{e.message}"
|
|
121
148
|
e.backtrace&.first(5)&.each { |line| warn " #{line}" }
|
|
@@ -125,6 +152,30 @@ module RailsConsoleAi
|
|
|
125
152
|
)
|
|
126
153
|
end
|
|
127
154
|
|
|
155
|
+
# When cap is nil or non-positive, run inline. Otherwise spawn a nested
|
|
156
|
+
# worker thread, join with the deadline, and kill + raise on overshoot.
|
|
157
|
+
# Kept localized (vs Timeout.timeout) so a runaway provider call can't
|
|
158
|
+
# raise from inside our own bookkeeping code.
|
|
159
|
+
def run_with_deadline(cap)
|
|
160
|
+
return yield if cap.nil? || cap.to_f <= 0
|
|
161
|
+
result = nil
|
|
162
|
+
error = nil
|
|
163
|
+
worker = Thread.new do
|
|
164
|
+
Thread.current.report_on_exception = false
|
|
165
|
+
begin
|
|
166
|
+
result = yield
|
|
167
|
+
rescue => e
|
|
168
|
+
error = e
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
if worker.join(cap.to_f).nil?
|
|
172
|
+
worker.kill
|
|
173
|
+
raise RunnerTimeoutError, "exceeded max_wall_clock_seconds (#{cap}s)"
|
|
174
|
+
end
|
|
175
|
+
raise error if error
|
|
176
|
+
result
|
|
177
|
+
end
|
|
178
|
+
|
|
128
179
|
# Build the `result` payload returned via get_agent_response. The
|
|
129
180
|
# LLM's prose lands in the channel's captured_output; the value the
|
|
130
181
|
# generated code returned lands in exec_result. Without including the
|
|
@@ -28,6 +28,10 @@ module RailsConsoleAi
|
|
|
28
28
|
create_attrs[:status] = attrs[:status] if attrs.key?(:status)
|
|
29
29
|
create_attrs[:result] = attrs[:result] if attrs.key?(:result)
|
|
30
30
|
create_attrs[:error_message] = attrs[:error_message] if attrs.key?(:error_message)
|
|
31
|
+
if attrs.key?(:options)
|
|
32
|
+
opts = attrs[:options]
|
|
33
|
+
create_attrs[:options] = opts.is_a?(String) ? opts : opts.to_json
|
|
34
|
+
end
|
|
31
35
|
record = session_class.create!(create_attrs)
|
|
32
36
|
record.id
|
|
33
37
|
rescue => e
|
|
@@ -122,15 +122,10 @@ module RailsConsoleAi
|
|
|
122
122
|
key = skill_key(name)
|
|
123
123
|
existing = load_skill_file(key)
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
bypasses = Array(bypass_guards_for_methods)
|
|
131
|
-
frontmatter['bypass_guards_for_methods'] = bypasses unless bypasses.empty?
|
|
132
|
-
|
|
133
|
-
content = "---\n#{YAML.dump(frontmatter).sub("---\n", '').strip}\n---\n\n#{body}\n"
|
|
125
|
+
content = self.class.dump(
|
|
126
|
+
name: name, description: description, body: body,
|
|
127
|
+
tags: tags, bypass_guards_for_methods: bypass_guards_for_methods
|
|
128
|
+
)
|
|
134
129
|
@storage.write(key, content)
|
|
135
130
|
|
|
136
131
|
path = @storage.respond_to?(:root_path) ? File.join(@storage.root_path, key) : key
|
|
@@ -190,5 +185,19 @@ module RailsConsoleAi
|
|
|
190
185
|
rescue Psych::SyntaxError
|
|
191
186
|
nil
|
|
192
187
|
end
|
|
188
|
+
|
|
189
|
+
# Inverse of parse: emit a canonical .md (frontmatter + body) string from
|
|
190
|
+
# structured attrs. Used by AI tool callers and file-fallback writers so
|
|
191
|
+
# the on-disk and DB representations stay byte-identical.
|
|
192
|
+
def self.dump(name:, description:, body:, tags: [], bypass_guards_for_methods: [])
|
|
193
|
+
frontmatter = {
|
|
194
|
+
'name' => name,
|
|
195
|
+
'description' => description,
|
|
196
|
+
'tags' => Array(tags)
|
|
197
|
+
}
|
|
198
|
+
bypasses = Array(bypass_guards_for_methods)
|
|
199
|
+
frontmatter['bypass_guards_for_methods'] = bypasses unless bypasses.empty?
|
|
200
|
+
"---\n#{YAML.dump(frontmatter).sub("---\n", '').strip}\n---\n\n#{body}\n"
|
|
201
|
+
end
|
|
193
202
|
end
|
|
194
203
|
end
|
|
@@ -68,14 +68,12 @@ module RailsConsoleAi
|
|
|
68
68
|
record = RailsConsoleAi::Skill.where('LOWER(name) = ?', name.to_s.downcase).first
|
|
69
69
|
record ||= RailsConsoleAi::Skill.new
|
|
70
70
|
was_new = record.new_record?
|
|
71
|
+
content = RailsConsoleAi::SkillLoader.dump(
|
|
72
|
+
name: name, description: description, body: body,
|
|
73
|
+
tags: tags, bypass_guards_for_methods: bypass_guards_for_methods
|
|
74
|
+
)
|
|
71
75
|
record.update_with_version!(
|
|
72
|
-
{
|
|
73
|
-
name: name,
|
|
74
|
-
description: description,
|
|
75
|
-
body: body,
|
|
76
|
-
tags: Array(tags),
|
|
77
|
-
bypass_guards_for_methods: Array(bypass_guards_for_methods)
|
|
78
|
-
},
|
|
76
|
+
{ content: content },
|
|
79
77
|
edited_by: edited_by,
|
|
80
78
|
change_note: change_note
|
|
81
79
|
)
|
|
@@ -114,12 +112,11 @@ module RailsConsoleAi
|
|
|
114
112
|
record = RailsConsoleAi::Memory.where('LOWER(name) = ?', name.to_s.downcase).first
|
|
115
113
|
record ||= RailsConsoleAi::Memory.new
|
|
116
114
|
was_new = record.new_record?
|
|
115
|
+
content = RailsConsoleAi::Tools::MemoryTools.dump(
|
|
116
|
+
name: name, description: description, tags: tags
|
|
117
|
+
)
|
|
117
118
|
record.update_with_version!(
|
|
118
|
-
{
|
|
119
|
-
name: name,
|
|
120
|
-
description: description,
|
|
121
|
-
tags: Array(tags)
|
|
122
|
-
},
|
|
119
|
+
{ content: content },
|
|
123
120
|
edited_by: edited_by,
|
|
124
121
|
change_note: change_note
|
|
125
122
|
)
|
|
@@ -158,15 +155,12 @@ module RailsConsoleAi
|
|
|
158
155
|
record = RailsConsoleAi::Agent.where('LOWER(name) = ?', name.to_s.downcase).first
|
|
159
156
|
record ||= RailsConsoleAi::Agent.new
|
|
160
157
|
was_new = record.new_record?
|
|
158
|
+
content = RailsConsoleAi::AgentLoader.dump(
|
|
159
|
+
name: name, description: description, body: body,
|
|
160
|
+
max_rounds: max_rounds, model: model, tools: tools
|
|
161
|
+
)
|
|
161
162
|
record.update_with_version!(
|
|
162
|
-
{
|
|
163
|
-
name: name,
|
|
164
|
-
description: description,
|
|
165
|
-
body: body,
|
|
166
|
-
max_rounds: max_rounds,
|
|
167
|
-
model: model,
|
|
168
|
-
tools: Array(tools)
|
|
169
|
-
},
|
|
163
|
+
{ content: content },
|
|
170
164
|
edited_by: edited_by,
|
|
171
165
|
change_note: change_note
|
|
172
166
|
)
|
|
@@ -211,6 +211,14 @@ module RailsConsoleAi
|
|
|
211
211
|
nil
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
+
# Inverse of parse: emit a canonical .md string. The DB store uses this
|
|
215
|
+
# minimal form (name + tags only in frontmatter); the file store layers
|
|
216
|
+
# created_at/updated_at on top via save_memory_to_file.
|
|
217
|
+
def self.dump(name:, description:, tags: [])
|
|
218
|
+
frontmatter = { 'name' => name, 'tags' => Array(tags) }
|
|
219
|
+
"---\n#{YAML.dump(frontmatter).sub("---\n", '').strip}\n---\n\n#{description}\n"
|
|
220
|
+
end
|
|
221
|
+
|
|
214
222
|
def find_memory_key_by_name(name)
|
|
215
223
|
keys = @storage.list("#{MEMORIES_DIR}/*.md")
|
|
216
224
|
keys.find do |key|
|
data/lib/rails_console_ai.rb
CHANGED
|
@@ -57,8 +57,17 @@ module RailsConsoleAi
|
|
|
57
57
|
|
|
58
58
|
# Enqueue an agent run. Returns the Integer session id immediately;
|
|
59
59
|
# the actual work is picked up by `rake rails_console_ai:agents`.
|
|
60
|
-
|
|
60
|
+
#
|
|
61
|
+
# use_thinking_model: run on the configured thinking-tier model
|
|
62
|
+
# max_wall_clock_seconds: hard kill the run after N seconds (nil = no cap)
|
|
63
|
+
def run_agent(query, name: nil, user_name: nil,
|
|
64
|
+
use_thinking_model: false,
|
|
65
|
+
max_wall_clock_seconds: 600)
|
|
61
66
|
require 'rails_console_ai/session_logger'
|
|
67
|
+
options = {
|
|
68
|
+
'use_thinking_model' => !!use_thinking_model,
|
|
69
|
+
'max_wall_clock_seconds' => max_wall_clock_seconds
|
|
70
|
+
}
|
|
62
71
|
id = SessionLogger.log(
|
|
63
72
|
query: query,
|
|
64
73
|
conversation: [],
|
|
@@ -66,7 +75,8 @@ module RailsConsoleAi
|
|
|
66
75
|
name: name,
|
|
67
76
|
user_name: user_name,
|
|
68
77
|
status: 'queued',
|
|
69
|
-
executed: false
|
|
78
|
+
executed: false,
|
|
79
|
+
options: options
|
|
70
80
|
)
|
|
71
81
|
raise 'Failed to enqueue agent run (session logging disabled or table missing)' unless id
|
|
72
82
|
id
|
|
@@ -145,6 +155,7 @@ module RailsConsoleAi
|
|
|
145
155
|
t.string :slack_thread_ts, limit: 255
|
|
146
156
|
t.string :slack_channel_name, limit: 255
|
|
147
157
|
t.integer :duration_ms
|
|
158
|
+
t.text :options
|
|
148
159
|
t.datetime :created_at, null: false
|
|
149
160
|
end
|
|
150
161
|
|
|
@@ -169,13 +180,22 @@ module RailsConsoleAi
|
|
|
169
180
|
skills_table = 'rails_console_ai_skills'
|
|
170
181
|
versions_table = 'rails_console_ai_skill_versions'
|
|
171
182
|
|
|
183
|
+
# Old shape had per-field columns (body, tags, bypass_guards_for_methods,
|
|
184
|
+
# description). New shape stores the raw .md in `content`. Pre-production,
|
|
185
|
+
# so we drop and recreate when the old shape is detected.
|
|
186
|
+
if conn.table_exists?(skills_table) && !conn.column_exists?(skills_table, :content)
|
|
187
|
+
conn.drop_table(skills_table)
|
|
188
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{skills_table} (replaced with single-content schema).\e[0m"
|
|
189
|
+
end
|
|
190
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :content)
|
|
191
|
+
conn.drop_table(versions_table)
|
|
192
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{versions_table}.\e[0m"
|
|
193
|
+
end
|
|
194
|
+
|
|
172
195
|
unless conn.table_exists?(skills_table)
|
|
173
196
|
conn.create_table(skills_table) do |t|
|
|
174
197
|
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
|
|
198
|
+
t.text :content, null: false
|
|
179
199
|
t.string :status, limit: 20, default: 'proposed', null: false
|
|
180
200
|
t.string :approved_by, limit: 255
|
|
181
201
|
t.datetime :approved_at
|
|
@@ -187,34 +207,13 @@ module RailsConsoleAi
|
|
|
187
207
|
conn.add_index(skills_table, :name, unique: true)
|
|
188
208
|
conn.add_index(skills_table, :status)
|
|
189
209
|
$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
210
|
end
|
|
209
211
|
|
|
210
212
|
unless conn.table_exists?(versions_table)
|
|
211
213
|
conn.create_table(versions_table) do |t|
|
|
212
214
|
t.integer :skill_id
|
|
213
215
|
t.string :name, limit: 255
|
|
214
|
-
t.text :
|
|
215
|
-
t.text :body
|
|
216
|
-
t.text :tags
|
|
217
|
-
t.text :bypass_guards_for_methods
|
|
216
|
+
t.text :content
|
|
218
217
|
t.string :status, limit: 20
|
|
219
218
|
t.string :edited_by, limit: 255
|
|
220
219
|
t.text :change_note
|
|
@@ -223,10 +222,6 @@ module RailsConsoleAi
|
|
|
223
222
|
conn.add_index(versions_table, :skill_id)
|
|
224
223
|
conn.add_index(versions_table, :created_at)
|
|
225
224
|
$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
225
|
end
|
|
231
226
|
end
|
|
232
227
|
|
|
@@ -234,11 +229,19 @@ module RailsConsoleAi
|
|
|
234
229
|
memories_table = 'rails_console_ai_memories'
|
|
235
230
|
versions_table = 'rails_console_ai_memory_versions'
|
|
236
231
|
|
|
232
|
+
if conn.table_exists?(memories_table) && !conn.column_exists?(memories_table, :content)
|
|
233
|
+
conn.drop_table(memories_table)
|
|
234
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{memories_table}.\e[0m"
|
|
235
|
+
end
|
|
236
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :content)
|
|
237
|
+
conn.drop_table(versions_table)
|
|
238
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{versions_table}.\e[0m"
|
|
239
|
+
end
|
|
240
|
+
|
|
237
241
|
unless conn.table_exists?(memories_table)
|
|
238
242
|
conn.create_table(memories_table) do |t|
|
|
239
243
|
t.string :name, limit: 255, null: false
|
|
240
|
-
t.text :
|
|
241
|
-
t.text :tags
|
|
244
|
+
t.text :content, null: false
|
|
242
245
|
t.integer :use_count, default: 0, null: false
|
|
243
246
|
t.datetime :last_used_at
|
|
244
247
|
t.datetime :created_at, null: false
|
|
@@ -246,21 +249,13 @@ module RailsConsoleAi
|
|
|
246
249
|
end
|
|
247
250
|
conn.add_index(memories_table, :name, unique: true)
|
|
248
251
|
$stdout.puts "\e[32mRailsConsoleAi: created #{memories_table} table.\e[0m"
|
|
249
|
-
else
|
|
250
|
-
unless conn.column_exists?(memories_table, :use_count)
|
|
251
|
-
conn.add_column(memories_table, :use_count, :integer, default: 0, null: false)
|
|
252
|
-
end
|
|
253
|
-
unless conn.column_exists?(memories_table, :last_used_at)
|
|
254
|
-
conn.add_column(memories_table, :last_used_at, :datetime)
|
|
255
|
-
end
|
|
256
252
|
end
|
|
257
253
|
|
|
258
254
|
unless conn.table_exists?(versions_table)
|
|
259
255
|
conn.create_table(versions_table) do |t|
|
|
260
256
|
t.integer :memory_id
|
|
261
257
|
t.string :name, limit: 255
|
|
262
|
-
t.text :
|
|
263
|
-
t.text :tags
|
|
258
|
+
t.text :content
|
|
264
259
|
t.string :edited_by, limit: 255
|
|
265
260
|
t.text :change_note
|
|
266
261
|
t.datetime :created_at, null: false
|
|
@@ -275,14 +270,19 @@ module RailsConsoleAi
|
|
|
275
270
|
agents_table = 'rails_console_ai_agents'
|
|
276
271
|
versions_table = 'rails_console_ai_agent_versions'
|
|
277
272
|
|
|
273
|
+
if conn.table_exists?(agents_table) && !conn.column_exists?(agents_table, :content)
|
|
274
|
+
conn.drop_table(agents_table)
|
|
275
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{agents_table}.\e[0m"
|
|
276
|
+
end
|
|
277
|
+
if conn.table_exists?(versions_table) && !conn.column_exists?(versions_table, :content)
|
|
278
|
+
conn.drop_table(versions_table)
|
|
279
|
+
$stdout.puts "\e[33mRailsConsoleAi: dropped legacy #{versions_table}.\e[0m"
|
|
280
|
+
end
|
|
281
|
+
|
|
278
282
|
unless conn.table_exists?(agents_table)
|
|
279
283
|
conn.create_table(agents_table) do |t|
|
|
280
284
|
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
|
|
285
|
+
t.text :content, null: false
|
|
286
286
|
t.string :status, limit: 20, default: 'proposed', null: false
|
|
287
287
|
t.string :approved_by, limit: 255
|
|
288
288
|
t.datetime :approved_at
|
|
@@ -294,34 +294,13 @@ module RailsConsoleAi
|
|
|
294
294
|
conn.add_index(agents_table, :name, unique: true)
|
|
295
295
|
conn.add_index(agents_table, :status)
|
|
296
296
|
$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
297
|
end
|
|
315
298
|
|
|
316
299
|
unless conn.table_exists?(versions_table)
|
|
317
300
|
conn.create_table(versions_table) do |t|
|
|
318
301
|
t.integer :agent_id
|
|
319
302
|
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
|
|
303
|
+
t.text :content
|
|
325
304
|
t.string :status, limit: 20
|
|
326
305
|
t.string :edited_by, limit: 255
|
|
327
306
|
t.text :change_note
|
|
@@ -376,6 +355,11 @@ module RailsConsoleAi
|
|
|
376
355
|
migrations << 'error_message'
|
|
377
356
|
end
|
|
378
357
|
|
|
358
|
+
unless conn.column_exists?(table, :options)
|
|
359
|
+
conn.add_column(table, :options, :text)
|
|
360
|
+
migrations << 'options'
|
|
361
|
+
end
|
|
362
|
+
|
|
379
363
|
unless conn.index_exists?(table, [:mode, :status], name: 'idx_rca_sessions_mode_status')
|
|
380
364
|
conn.add_index(table, [:mode, :status], name: 'idx_rca_sessions_mode_status')
|
|
381
365
|
migrations << 'idx_rca_sessions_mode_status'
|