console_agent 0.9.0 → 0.11.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 +26 -0
- data/README.md +104 -2
- data/app/helpers/console_agent/sessions_helper.rb +14 -0
- data/app/models/console_agent/session.rb +1 -1
- data/app/views/console_agent/sessions/index.html.erb +4 -4
- data/app/views/console_agent/sessions/show.html.erb +16 -6
- data/app/views/layouts/console_agent/application.html.erb +1 -0
- data/lib/console_agent/channel/base.rb +23 -0
- data/lib/console_agent/channel/console.rb +457 -0
- data/lib/console_agent/channel/slack.rb +182 -0
- data/lib/console_agent/configuration.rb +73 -5
- data/lib/console_agent/conversation_engine.rb +1122 -0
- data/lib/console_agent/executor.rb +257 -44
- data/lib/console_agent/providers/base.rb +23 -15
- data/lib/console_agent/providers/local.rb +112 -0
- data/lib/console_agent/railtie.rb +4 -0
- data/lib/console_agent/repl.rb +27 -1128
- data/lib/console_agent/safety_guards.rb +207 -0
- data/lib/console_agent/session_logger.rb +14 -3
- data/lib/console_agent/slack_bot.rb +465 -0
- data/lib/console_agent/tools/registry.rb +66 -16
- data/lib/console_agent/version.rb +1 -1
- data/lib/console_agent.rb +17 -3
- data/lib/generators/console_agent/templates/initializer.rb +30 -1
- data/lib/tasks/console_agent.rake +7 -0
- metadata +9 -1
|
@@ -8,9 +8,10 @@ module ConsoleAgent
|
|
|
8
8
|
# Tools that should never be cached (side effects or user interaction)
|
|
9
9
|
NO_CACHE = %w[ask_user save_memory delete_memory execute_plan].freeze
|
|
10
10
|
|
|
11
|
-
def initialize(executor: nil, mode: :default)
|
|
11
|
+
def initialize(executor: nil, mode: :default, channel: nil)
|
|
12
12
|
@executor = executor
|
|
13
13
|
@mode = mode
|
|
14
|
+
@channel = channel
|
|
14
15
|
@definitions = []
|
|
15
16
|
@handlers = {}
|
|
16
17
|
@cache = {}
|
|
@@ -170,6 +171,24 @@ module ConsoleAgent
|
|
|
170
171
|
handler: ->(args) { code.search_code(args['query'], args['directory']) }
|
|
171
172
|
)
|
|
172
173
|
|
|
174
|
+
if @executor
|
|
175
|
+
register(
|
|
176
|
+
name: 'recall_output',
|
|
177
|
+
description: 'Retrieve a previous code execution output that was omitted from the conversation to save context. Use the output id shown in the "[Output omitted]" placeholder.',
|
|
178
|
+
parameters: {
|
|
179
|
+
'type' => 'object',
|
|
180
|
+
'properties' => {
|
|
181
|
+
'id' => { 'type' => 'integer', 'description' => 'The output id to retrieve' }
|
|
182
|
+
},
|
|
183
|
+
'required' => ['id']
|
|
184
|
+
},
|
|
185
|
+
handler: ->(args) {
|
|
186
|
+
result = @executor.recall_output(args['id'].to_i)
|
|
187
|
+
result || "No output found with id #{args['id']}"
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
end
|
|
191
|
+
|
|
173
192
|
unless @mode == :init
|
|
174
193
|
register(
|
|
175
194
|
name: 'ask_user',
|
|
@@ -284,8 +303,12 @@ module ConsoleAgent
|
|
|
284
303
|
# Ask for plan approval (unless auto-execute)
|
|
285
304
|
skip_confirmations = auto
|
|
286
305
|
unless auto
|
|
287
|
-
|
|
288
|
-
|
|
306
|
+
if @channel
|
|
307
|
+
answer = @channel.confirm(" Accept plan? [y/N/a(uto)] ")
|
|
308
|
+
else
|
|
309
|
+
$stdout.print "\e[33m Accept plan? [y/N/a(uto)] \e[0m"
|
|
310
|
+
answer = $stdin.gets.to_s.strip.downcase
|
|
311
|
+
end
|
|
289
312
|
case answer
|
|
290
313
|
when 'a', 'auto'
|
|
291
314
|
skip_confirmations = true
|
|
@@ -308,8 +331,12 @@ module ConsoleAgent
|
|
|
308
331
|
|
|
309
332
|
# Per-step confirmation (unless auto-execute or plan-level auto)
|
|
310
333
|
unless skip_confirmations
|
|
311
|
-
|
|
312
|
-
|
|
334
|
+
if @channel
|
|
335
|
+
step_answer = @channel.confirm(" Run? [y/N/edit] ")
|
|
336
|
+
else
|
|
337
|
+
$stdout.print "\e[33m Run? [y/N/edit] \e[0m"
|
|
338
|
+
step_answer = $stdin.gets.to_s.strip.downcase
|
|
339
|
+
end
|
|
313
340
|
|
|
314
341
|
case step_answer
|
|
315
342
|
when 'e', 'edit'
|
|
@@ -317,8 +344,12 @@ module ConsoleAgent
|
|
|
317
344
|
if edited && edited != step['code']
|
|
318
345
|
$stdout.puts "\e[33m # Edited code:\e[0m"
|
|
319
346
|
$stdout.puts highlight_plan_code(edited)
|
|
320
|
-
|
|
321
|
-
|
|
347
|
+
if @channel
|
|
348
|
+
confirm = @channel.confirm(" Run edited code? [y/N] ")
|
|
349
|
+
else
|
|
350
|
+
$stdout.print "\e[33m Run edited code? [y/N] \e[0m"
|
|
351
|
+
confirm = $stdin.gets.to_s.strip.downcase
|
|
352
|
+
end
|
|
322
353
|
unless confirm == 'y' || confirm == 'yes'
|
|
323
354
|
feedback = ask_feedback("What would you like changed?")
|
|
324
355
|
results << "Step #{i + 1}: User declined after edit. Feedback: #{feedback}"
|
|
@@ -336,6 +367,17 @@ module ConsoleAgent
|
|
|
336
367
|
end
|
|
337
368
|
|
|
338
369
|
exec_result = @executor.execute(step['code'])
|
|
370
|
+
|
|
371
|
+
# On safety error, offer to re-run with guards disabled (console only)
|
|
372
|
+
if @executor.last_safety_error
|
|
373
|
+
if @channel && !@channel.supports_danger?
|
|
374
|
+
results << "Step #{i + 1} (#{step['description']}):\nBLOCKED by safety guard: #{@executor.last_error}. Write operations are not permitted in this channel."
|
|
375
|
+
break
|
|
376
|
+
else
|
|
377
|
+
exec_result = @executor.offer_danger_retry(step['code'])
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
339
381
|
# Make result available as step1, step2, etc. for subsequent steps
|
|
340
382
|
@executor.binding_context.local_variable_set(:"step#{i + 1}", exec_result)
|
|
341
383
|
output = @executor.last_output
|
|
@@ -389,18 +431,26 @@ module ConsoleAgent
|
|
|
389
431
|
end
|
|
390
432
|
|
|
391
433
|
def ask_feedback(prompt)
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
434
|
+
if @channel
|
|
435
|
+
@channel.prompt(" #{prompt} > ")
|
|
436
|
+
else
|
|
437
|
+
$stdout.print "\e[36m #{prompt} > \e[0m"
|
|
438
|
+
feedback = $stdin.gets
|
|
439
|
+
return '(no feedback provided)' if feedback.nil?
|
|
440
|
+
feedback.strip.empty? ? '(no feedback provided)' : feedback.strip
|
|
441
|
+
end
|
|
396
442
|
end
|
|
397
443
|
|
|
398
444
|
def ask_user(question)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
445
|
+
if @channel
|
|
446
|
+
@channel.prompt(" ? #{question}\n > ")
|
|
447
|
+
else
|
|
448
|
+
$stdout.puts "\e[36m ? #{question}\e[0m"
|
|
449
|
+
$stdout.print "\e[36m > \e[0m"
|
|
450
|
+
answer = $stdin.gets
|
|
451
|
+
return '(no answer provided)' if answer.nil?
|
|
452
|
+
answer.strip.empty? ? '(no answer provided)' : answer.strip
|
|
453
|
+
end
|
|
404
454
|
end
|
|
405
455
|
|
|
406
456
|
def register(name:, description:, parameters:, handler:)
|
data/lib/console_agent.rb
CHANGED
|
@@ -58,8 +58,8 @@ module ConsoleAgent
|
|
|
58
58
|
def status
|
|
59
59
|
c = configuration
|
|
60
60
|
key = c.resolved_api_key
|
|
61
|
-
masked_key = if key.nil? || key.empty?
|
|
62
|
-
"\e[31m(not set)\e[0m"
|
|
61
|
+
masked_key = if key.nil? || key.empty? || key == 'no-key'
|
|
62
|
+
c.provider == :local ? "\e[32m(not required)\e[0m" : "\e[31m(not set)\e[0m"
|
|
63
63
|
else
|
|
64
64
|
key[0..6] + '...' + key[-4..-1]
|
|
65
65
|
end
|
|
@@ -69,11 +69,19 @@ module ConsoleAgent
|
|
|
69
69
|
lines << " Provider: #{c.provider}"
|
|
70
70
|
lines << " Model: #{c.resolved_model}"
|
|
71
71
|
lines << " API key: #{masked_key}"
|
|
72
|
-
lines << "
|
|
72
|
+
lines << " Local URL: #{c.local_url}" if c.provider == :local
|
|
73
|
+
lines << " Max tokens: #{c.max_tokens || '(auto)'}"
|
|
73
74
|
lines << " Temperature: #{c.temperature}"
|
|
74
75
|
lines << " Timeout: #{c.timeout}s"
|
|
75
76
|
lines << " Max tool rounds:#{c.max_tool_rounds}"
|
|
76
77
|
lines << " Auto-execute: #{c.auto_execute}"
|
|
78
|
+
guards = c.safety_guards
|
|
79
|
+
if guards.empty?
|
|
80
|
+
lines << " Safe mode: \e[33m(no guards configured)\e[0m"
|
|
81
|
+
else
|
|
82
|
+
status = guards.enabled? ? "\e[32mON\e[0m" : "\e[31mOFF\e[0m"
|
|
83
|
+
lines << " Safe mode: #{status} (#{guards.names.join(', ')})"
|
|
84
|
+
end
|
|
77
85
|
lines << " Memories: #{c.memories_enabled}"
|
|
78
86
|
lines << " Session logging:#{session_table_status}"
|
|
79
87
|
lines << " Debug: #{c.debug}"
|
|
@@ -134,6 +142,12 @@ module ConsoleAgent
|
|
|
134
142
|
migrations << 'name'
|
|
135
143
|
end
|
|
136
144
|
|
|
145
|
+
unless conn.column_exists?(table, :slack_thread_ts)
|
|
146
|
+
conn.add_column(table, :slack_thread_ts, :string, limit: 255)
|
|
147
|
+
conn.add_index(table, :slack_thread_ts) unless conn.index_exists?(table, :slack_thread_ts)
|
|
148
|
+
migrations << 'slack_thread_ts'
|
|
149
|
+
end
|
|
150
|
+
|
|
137
151
|
if migrations.empty?
|
|
138
152
|
$stdout.puts "\e[32mConsoleAgent: #{table} is up to date.\e[0m"
|
|
139
153
|
else
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
ConsoleAgent.configure do |config|
|
|
2
|
-
# LLM provider: :anthropic or :
|
|
2
|
+
# LLM provider: :anthropic, :openai, or :local
|
|
3
3
|
config.provider = :anthropic
|
|
4
4
|
|
|
5
5
|
# API key (or set ANTHROPIC_API_KEY / OPENAI_API_KEY env var)
|
|
@@ -23,6 +23,12 @@ ConsoleAgent.configure do |config|
|
|
|
23
23
|
# HTTP timeout in seconds
|
|
24
24
|
config.timeout = 30
|
|
25
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
|
+
|
|
26
32
|
# Debug mode: prints full API requests/responses and tool calls to stderr
|
|
27
33
|
# config.debug = true
|
|
28
34
|
|
|
@@ -38,4 +44,27 @@ ConsoleAgent.configure do |config|
|
|
|
38
44
|
# When nil, all requests are denied. Set credentials or use config.authenticate.
|
|
39
45
|
# config.admin_username = 'admin'
|
|
40
46
|
# config.admin_password = 'changeme'
|
|
47
|
+
|
|
48
|
+
# Safety guards: prevent side effects (DB writes, HTTP calls, etc.) during code execution.
|
|
49
|
+
# When enabled, code runs in safe mode by default. Users can toggle with /danger in the REPL.
|
|
50
|
+
#
|
|
51
|
+
# Built-in guard for database writes (works on Rails 5+, all adapters):
|
|
52
|
+
# config.use_builtin_safety_guard :database_writes
|
|
53
|
+
#
|
|
54
|
+
# Built-in guard for HTTP mutations — blocks POST/PUT/PATCH/DELETE via Net::HTTP.
|
|
55
|
+
# Covers most Ruby HTTP libraries (HTTParty, RestClient, Faraday) since they use Net::HTTP:
|
|
56
|
+
# config.use_builtin_safety_guard :http_mutations
|
|
57
|
+
#
|
|
58
|
+
# Allowlist specific hosts or tables so they pass through without blocking:
|
|
59
|
+
# config.use_builtin_safety_guard :http_mutations,
|
|
60
|
+
# allow: [/s3\.amazonaws\.com/, /googleapis\.com/]
|
|
61
|
+
# config.use_builtin_safety_guard :database_writes,
|
|
62
|
+
# allow: ['console_agent_sessions']
|
|
63
|
+
#
|
|
64
|
+
# Built-in guard for mailers — disables ActionMailer delivery:
|
|
65
|
+
# config.use_builtin_safety_guard :mailers
|
|
66
|
+
#
|
|
67
|
+
# config.safety_guard :jobs do |&execute|
|
|
68
|
+
# Sidekiq::Testing.fake! { execute.call }
|
|
69
|
+
# end
|
|
41
70
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: console_agent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cortfr
|
|
@@ -98,17 +98,24 @@ files:
|
|
|
98
98
|
- app/views/layouts/console_agent/application.html.erb
|
|
99
99
|
- config/routes.rb
|
|
100
100
|
- lib/console_agent.rb
|
|
101
|
+
- lib/console_agent/channel/base.rb
|
|
102
|
+
- lib/console_agent/channel/console.rb
|
|
103
|
+
- lib/console_agent/channel/slack.rb
|
|
101
104
|
- lib/console_agent/configuration.rb
|
|
102
105
|
- lib/console_agent/console_methods.rb
|
|
103
106
|
- lib/console_agent/context_builder.rb
|
|
107
|
+
- lib/console_agent/conversation_engine.rb
|
|
104
108
|
- lib/console_agent/engine.rb
|
|
105
109
|
- lib/console_agent/executor.rb
|
|
106
110
|
- lib/console_agent/providers/anthropic.rb
|
|
107
111
|
- lib/console_agent/providers/base.rb
|
|
112
|
+
- lib/console_agent/providers/local.rb
|
|
108
113
|
- lib/console_agent/providers/openai.rb
|
|
109
114
|
- lib/console_agent/railtie.rb
|
|
110
115
|
- lib/console_agent/repl.rb
|
|
116
|
+
- lib/console_agent/safety_guards.rb
|
|
111
117
|
- lib/console_agent/session_logger.rb
|
|
118
|
+
- lib/console_agent/slack_bot.rb
|
|
112
119
|
- lib/console_agent/storage/base.rb
|
|
113
120
|
- lib/console_agent/storage/file_storage.rb
|
|
114
121
|
- lib/console_agent/tools/code_tools.rb
|
|
@@ -119,6 +126,7 @@ files:
|
|
|
119
126
|
- lib/console_agent/version.rb
|
|
120
127
|
- lib/generators/console_agent/install_generator.rb
|
|
121
128
|
- lib/generators/console_agent/templates/initializer.rb
|
|
129
|
+
- lib/tasks/console_agent.rake
|
|
122
130
|
homepage: https://github.com/cortfr/console_agent
|
|
123
131
|
licenses:
|
|
124
132
|
- MIT
|