Class: Nanobot::Agent::Loop
- Inherits:
-
Object
- Object
- Nanobot::Agent::Loop
- Defined in:
- lib/nanobot/agent/loop.rb
Overview
AgentLoop is the core processing engine that handles message->response pipeline
Constant Summary collapse
- LOCAL_CHANNELS =
Channels considered local (full tool access by default)
%w[cli].freeze
Instance Attribute Summary collapse
-
#bus ⇒ Object
readonly
Returns the value of attribute bus.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#provider ⇒ Object
readonly
Returns the value of attribute provider.
-
#workspace ⇒ Object
readonly
Returns the value of attribute workspace.
Instance Method Summary collapse
-
#initialize(bus:, provider:, workspace:, logger: nil, **opts) ⇒ Loop
constructor
A new instance of Loop.
-
#process_direct(content, channel: 'cli', chat_id: 'default') ⇒ String
Process a single message directly (for CLI/testing).
-
#process_message(msg) ⇒ Bus::OutboundMessage?
Process a message and return a response This method orchestrates message processing and requires complexity.
-
#run ⇒ Object
Start the agent loop (consumes from bus).
-
#stop ⇒ Object
Stop the agent loop.
Constructor Details
#initialize(bus:, provider:, workspace:, logger: nil, **opts) ⇒ Loop
Returns a new instance of Loop.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/nanobot/agent/loop.rb', line 26 def initialize(bus:, provider:, workspace:, logger: nil, **opts) @bus = bus @provider = provider @workspace = Pathname.new(workspace). @model = opts[:model] || provider.default_model @max_iterations = opts[:max_iterations] || 20 @brave_api_key = opts[:brave_api_key] @exec_config = opts[:exec_config] || {} @restrict_to_workspace = opts.fetch(:restrict_to_workspace, true) @confirm_tool_call = opts[:confirm_tool_call] @schedule_store = opts[:schedule_store] @logger = logger || Logger.new(IO::NULL) @context = ContextBuilder.new(@workspace, logger: @logger) @sessions = Session::Manager.new(@workspace) @running = false register_default_tools end |
Instance Attribute Details
#bus ⇒ Object (readonly)
Returns the value of attribute bus.
12 13 14 |
# File 'lib/nanobot/agent/loop.rb', line 12 def bus @bus end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
12 13 14 |
# File 'lib/nanobot/agent/loop.rb', line 12 def logger @logger end |
#provider ⇒ Object (readonly)
Returns the value of attribute provider.
12 13 14 |
# File 'lib/nanobot/agent/loop.rb', line 12 def provider @provider end |
#workspace ⇒ Object (readonly)
Returns the value of attribute workspace.
12 13 14 |
# File 'lib/nanobot/agent/loop.rb', line 12 def workspace @workspace end |
Instance Method Details
#process_direct(content, channel: 'cli', chat_id: 'default') ⇒ String
Process a single message directly (for CLI/testing)
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/nanobot/agent/loop.rb', line 78 def process_direct(content, channel: 'cli', chat_id: 'default') msg = Bus::InboundMessage.new( channel: channel, sender_id: 'user', chat_id: chat_id, content: content ) response = (msg) response&.content end |
#process_message(msg) ⇒ Bus::OutboundMessage?
Process a message and return a response This method orchestrates message processing and requires complexity
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/nanobot/agent/loop.rb', line 94 def (msg) @logger.info "Processing message from #{msg.channel}:#{msg.chat_id}" # Handle slash commands before LLM processing slash_response = handle_slash_command(msg) return slash_response if slash_response # Get or create session session = @sessions.get_or_create(msg.session_key) # Build messages for LLM = @context.( history: session.get_history, current_message: msg.content, channel: msg.channel, chat_id: msg.chat_id ) # Save user message to session session.('user', msg.content) # Agent loop (also saves intermediate tool call messages to session) final_content = agent_loop(, session: session, channel: msg.channel) # Save final assistant response to session session.('assistant', final_content) @sessions.save(session) # Return response Bus::OutboundMessage.new( channel: msg.channel, chat_id: msg.chat_id, content: final_content ) rescue StandardError => e handle_processing_error(msg, e) end |
#run ⇒ Object
Start the agent loop (consumes from bus)
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/nanobot/agent/loop.rb', line 47 def run @running = true @logger.info 'Agent loop started' loop do break unless @running begin msg = @bus.consume_inbound(timeout: 1) next unless msg response = (msg) @bus.publish_outbound(response) if response rescue StandardError => e @logger.error "Error processing message: #{e.}" @logger.error e.backtrace.join("\n") end end end |
#stop ⇒ Object
Stop the agent loop
68 69 70 71 |
# File 'lib/nanobot/agent/loop.rb', line 68 def stop @running = false @logger.info 'Agent loop stopping' end |