Class: Ask::Agent::Extensions::Permissions

Inherits:
Object
  • Object
show all
Defined in:
lib/ask/agent/extensions/permissions.rb

Constant Summary collapse

DEFAULT_TOOLS =
%i[write edit bash destroy].freeze
ACCESS_MODES =
{
  full_access:       { blocked_tools: [] }.freeze,
  ask_before_changes: { blocked_tools: DEFAULT_TOOLS }.freeze,
  read_only:         { blocked_tools: %i[write edit bash destroy] }.freeze
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(mode: nil, blocked_tools: nil, timeout: nil) ⇒ Permissions

Returns a new instance of Permissions.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/ask/agent/extensions/permissions.rb', line 15

def initialize(mode: nil, blocked_tools: nil, timeout: nil)
  @mode = mode
  @timeout = timeout
  @pending = {}
  @mutex = Mutex.new

  @blocked_tools = if mode
    config = ACCESS_MODES[mode]
    raise ArgumentError, "Unknown access mode: #{mode.inspect}. Valid: #{ACCESS_MODES.keys.join(', ')}" unless config
    config[:blocked_tools].dup
  elsif blocked_tools
    Array(blocked_tools).map(&:to_sym)
  else
    DEFAULT_TOOLS.dup
  end
end

Instance Method Details

#approve(tool_call_id) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/ask/agent/extensions/permissions.rb', line 42

def approve(tool_call_id)
  @mutex.synchronize do
    entry = @pending[tool_call_id]
    return false unless entry
    entry[:approved] = true
  end
end

#before_tool_call(tool_call, _context) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/ask/agent/extensions/permissions.rb', line 32

def before_tool_call(tool_call, _context)
  return { action: :proceed } unless @blocked_tools.include?(tool_call.name.to_sym)

  if approved?(tool_call)
    { action: :proceed }
  else
    request_approval(tool_call)
  end
end

#pending_approvalsObject



50
51
52
# File 'lib/ask/agent/extensions/permissions.rb', line 50

def pending_approvals
  @mutex.synchronize { @pending.values.reject { |e| e[:approved] } }
end