Class: Rubino::Tools::MemoryTool
- Defined in:
- lib/rubino/tools/memory_tool.rb
Overview
Agent-callable interface to the memory store.
The agent uses this to record durable facts about the user or project across sessions. The schema is deliberately tiny — three actions, two targets — because every additional knob is another surface a prompt-injection attempt can probe. Threat scanning and the char-budget run inside Memory::Store; this tool only handles the action/target mapping and translates Store exceptions into tool-protocol error strings.
Constant Summary collapse
- VALID_ACTIONS =
%w[add replace remove].freeze
- VALID_TARGETS =
%w[memory user].freeze
- TARGET_TO_KIND =
target → memory kind. “user” is the user_profile slot; “memory” is the catch-all “fact” kind. Other kinds (preference, technical_decision, …) are reserved for the auto-extractor — the agent does not get to write to them directly through this tool.
{ "memory" => "fact", "user" => "user_profile" }.freeze
Instance Attribute Summary
Attributes inherited from Base
#cancel_token, #read_tracker, #stream_chunk
Instance Method Summary collapse
- #call(arguments) ⇒ Object
- #description ⇒ Object
-
#initialize(backend: nil) ⇒ MemoryTool
constructor
A new instance of MemoryTool.
- #input_schema ⇒ Object
- #name ⇒ Object
- #risk_level ⇒ Object
Methods inherited from Base
#cancellation_requested?, #config_key, #emit_chunk, #risky?, #to_tool_definition, workspace_root, workspace_roots
Constructor Details
#initialize(backend: nil) ⇒ MemoryTool
Returns a new instance of MemoryTool.
24 25 26 |
# File 'lib/rubino/tools/memory_tool.rb', line 24 def initialize(backend: nil) @backend = backend end |
Instance Method Details
#call(arguments) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/rubino/tools/memory_tool.rb', line 86 def call(arguments) args = symbolize(arguments) action = args[:action].to_s target = args[:target].to_s return error("invalid action '#{action}'; expected one of #{VALID_ACTIONS.join(", ")}") \ unless VALID_ACTIONS.include?(action) return error("invalid target '#{target}'; expected one of #{VALID_TARGETS.join(", ")}") \ unless VALID_TARGETS.include?(target) kind = TARGET_TO_KIND.fetch(target) case action when "add" then do_add(kind, args[:content]) when "replace" then do_replace(kind, args[:old_text], args[:content]) when "remove" then do_remove(kind, args[:old_text]) end end |
#description ⇒ Object
32 33 34 35 36 37 38 39 40 41 |
# File 'lib/rubino/tools/memory_tool.rb', line 32 def description "Persist facts across sessions. Use action=add to record a new fact, " \ "replace to update an existing fact (substring match on old_text), " \ "or remove to delete one. target=user writes to the user profile; " \ "target=memory writes to general memory. " \ "Store ONE atomic fact per call — make separate calls for separate " \ "facts so each can be superseded or forgotten independently. " \ "Content is scanned for prompt-injection / exfiltration patterns and " \ "subject to a character budget — refusals are reported in the output." end |
#input_schema ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/rubino/tools/memory_tool.rb', line 43 def input_schema { type: "object", properties: { action: { type: "string", enum: VALID_ACTIONS, description: "add, replace, or remove" }, target: { type: "string", enum: VALID_TARGETS, description: "memory (general) or user (user profile)" }, content: { type: "string", description: "New content (required for add and replace)" }, old_text: { type: "string", description: "Substring of existing memory to match " \ "(required for replace and remove)" } }, required: %w[action target] } end |
#name ⇒ Object
28 29 30 |
# File 'lib/rubino/tools/memory_tool.rb', line 28 def name "memory" end |
#risk_level ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/rubino/tools/memory_tool.rb', line 71 def risk_level # Memory store/retrieve/update is an internal, low-risk operation: # an autonomous "scratchpad" the agent maintains, not an external # side-effect like editing the user's files or running a shell # command. It must not trip the approval gate. Every write is # already threat-scanned and char-budgeted inside Memory::Store, # and the only destructive action (remove) deletes a SINGLE entry # by substring match — there is no full-wipe op exposed here — so # there is nothing left for an approval prompt to guard. # :low keeps it autonomous even under approvals.mode: manual # (Base#risky? only flags :medium/:high), matching how todo_tool # and other internal state-mutating tools stay unprompted. :low end |