Module: Vangrail::ConversationTools

Included in:
Conversation
Defined in:
lib/vangrail/conversation_tools.rb

Overview

Planning and monitored tool execution for a Conversation.

Instance Method Summary collapse

Instance Method Details

#admit?(capability, arguments: nil) ⇒ Boolean

Compatibility query for the coarse Admission API. Actual execution also requires a matching structured Grant from the ReferenceMonitor.

Returns:

  • (Boolean)


32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/vangrail/conversation_tools.rb', line 32

def admit?(capability, arguments: nil)
  turn = last_user_turn
  return false unless turn
  return false if profile.denied?(capability)

  args = case arguments
         when nil then nil
         when Cell then arguments
         else Cell.data(arguments)
         end
  admission.permit?(capability, request: Cell.user(turn.text, capabilities: capabilities),
                                arguments: args)
end

#child_env(source = ENV) ⇒ Object



85
86
87
# File 'lib/vangrail/conversation_tools.rb', line 85

def child_env(source = ENV)
  profile.strip_secrets? ? Profile.strip_secrets(source) : source.to_h
end

#confirm(call, actor:) ⇒ Object



81
82
83
# File 'lib/vangrail/conversation_tools.rb', line 81

def confirm(call, actor:)
  monitor.confirm(call, actor: actor)
end

#intend(*names) ⇒ Object

Names the tools this question is allowed to use before retrieved data is visible. Selecting a name never creates a Grant.

Raises:



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/vangrail/conversation_tools.rb', line 8

def intend(*names)
  raise Error, 'ask before intending a tool' unless last_user_turn
  raise PrivilegeError, 'the plan is locked: data has already been seen' if locked?

  names.each do |name|
    name = name.to_sym
    raise ArgumentError, "unknown tool #{name}" unless tools.key?(name)
    raise PrivilegeError, "capability #{name} is denied by profile" if profile.denied?(name)

    @intended << name unless @intended.include?(name)
  end
  intended
end

#intendedObject



22
23
24
# File 'lib/vangrail/conversation_tools.rb', line 22

def intended
  @intended.dup.freeze
end

#invoke(target, arguments: nil, sink: nil, confirmation: nil, transaction: false, idempotency_key: nil, risk: nil) ⇒ Object

Runs a handler only after profile, plan, hook, and reference-monitor authorization agree. Every refusal is recorded without calling the handler.

Raises:

  • (ArgumentError)


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/vangrail/conversation_tools.rb', line 49

def invoke(target, arguments: nil, sink: nil, confirmation: nil, transaction: false,
           idempotency_key: nil, risk: nil)
  call = target if target.is_a?(Call)
  name = call ? call.tool : target.to_sym
  raise ArgumentError, "unknown tool #{name}" unless tools.key?(name)

  handler_arguments = call ? call.arguments.raw : arguments
  call ||= build_call(name, arguments, sink: sink, confirmation: confirmation,
                                       transaction: transaction,
                                       idempotency_key: idempotency_key)
  refusal = preauthorization_refusal(name, handler_arguments, call)
  return refusal if refusal

  begin
    prepared = tools.prepare_transaction(name, handler_arguments, self, call: call)
  rescue StandardError => e
    return refuse(name, handler_arguments, 'transaction_prepare',
                  "#{e.class}: #{e.message}", call: call)
  end
  authorization = monitor.authorize(call, risk: risk)
  if authorization.denied?
    tools.rollback_transaction(prepared, self)
    return authorization_refusal(name, handler_arguments, call, authorization)
  end

  execute_authorized(name, handler_arguments, call, authorization, prepared)
end

#invoked?(name) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/vangrail/conversation_tools.rb', line 77

def invoked?(name)
  invocations.any? { |row| row[:name] == name.to_sym && row[:result].allowed? }
end

#locked?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/vangrail/conversation_tools.rb', line 26

def locked?
  @locked
end