console_agent 0.10.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 +11 -0
- data/README.md +98 -1
- 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 +239 -47
- data/lib/console_agent/providers/base.rb +7 -2
- data/lib/console_agent/providers/local.rb +112 -0
- data/lib/console_agent/railtie.rb +4 -0
- data/lib/console_agent/repl.rb +26 -1291
- 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 +48 -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 = {}
|
|
@@ -302,8 +303,12 @@ module ConsoleAgent
|
|
|
302
303
|
# Ask for plan approval (unless auto-execute)
|
|
303
304
|
skip_confirmations = auto
|
|
304
305
|
unless auto
|
|
305
|
-
|
|
306
|
-
|
|
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
|
|
307
312
|
case answer
|
|
308
313
|
when 'a', 'auto'
|
|
309
314
|
skip_confirmations = true
|
|
@@ -326,8 +331,12 @@ module ConsoleAgent
|
|
|
326
331
|
|
|
327
332
|
# Per-step confirmation (unless auto-execute or plan-level auto)
|
|
328
333
|
unless skip_confirmations
|
|
329
|
-
|
|
330
|
-
|
|
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
|
|
331
340
|
|
|
332
341
|
case step_answer
|
|
333
342
|
when 'e', 'edit'
|
|
@@ -335,8 +344,12 @@ module ConsoleAgent
|
|
|
335
344
|
if edited && edited != step['code']
|
|
336
345
|
$stdout.puts "\e[33m # Edited code:\e[0m"
|
|
337
346
|
$stdout.puts highlight_plan_code(edited)
|
|
338
|
-
|
|
339
|
-
|
|
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
|
|
340
353
|
unless confirm == 'y' || confirm == 'yes'
|
|
341
354
|
feedback = ask_feedback("What would you like changed?")
|
|
342
355
|
results << "Step #{i + 1}: User declined after edit. Feedback: #{feedback}"
|
|
@@ -354,6 +367,17 @@ module ConsoleAgent
|
|
|
354
367
|
end
|
|
355
368
|
|
|
356
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
|
+
|
|
357
381
|
# Make result available as step1, step2, etc. for subsequent steps
|
|
358
382
|
@executor.binding_context.local_variable_set(:"step#{i + 1}", exec_result)
|
|
359
383
|
output = @executor.last_output
|
|
@@ -407,18 +431,26 @@ module ConsoleAgent
|
|
|
407
431
|
end
|
|
408
432
|
|
|
409
433
|
def ask_feedback(prompt)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
|
414
442
|
end
|
|
415
443
|
|
|
416
444
|
def ask_user(question)
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
|
422
454
|
end
|
|
423
455
|
|
|
424
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
|