Class: AnalyticalBrain::Runner
- Inherits:
-
Object
- Object
- AnalyticalBrain::Runner
- Defined in:
- lib/analytical_brain/runner.rb
Overview
Orchestrates the analytical brain — a phantom (non-persisted) LLM loop that observes a session and performs background maintenance via tools.
The brain’s capabilities are assembled from independent Responsibility modules, each contributing a prompt section and tools. Which modules are active depends on the session type:
-
**Parent sessions** — session naming, skill/workflow/goal management
-
**Child sessions** — sub-agent nickname assignment, skill/workflow/goal management
Tools mutate the observed session directly (e.g. renaming it, activating skills), but no trace of the brain’s reasoning is persisted — events are emitted into a phantom session (session_id: nil).
Defined Under Namespace
Classes: Responsibility
Constant Summary collapse
- RESPONSIBILITIES =
{ session_naming: Responsibility.new( prompt: <<~PROMPT, ────────────────────────────── SESSION NAMING ────────────────────────────── Name the session when the topic becomes clear. Rename if it shifts. Format: one emoji + 1-3 descriptive words. PROMPT tools: [Tools::RenameSession] ), sub_agent_naming: Responsibility.new( prompt: <<~PROMPT, ────────────────────────────── SUB-AGENT NAMING ────────────────────────────── Give this sub-agent a memorable nickname based on its task. Format: 1-3 lowercase words joined by hyphens (e.g. "loop-sleuth", "api-scout"). Evocative, fun, easy to type after @. One nickname per call. If taken, pick another — no numeric suffixes. PROMPT tools: [Tools::AssignNickname] ), skill_management: Responsibility.new( prompt: <<~PROMPT, ────────────────────────────── SKILL MANAGEMENT ────────────────────────────── Activate skills when the conversation enters their domain. Deactivate when the agent moves to a different domain. Multiple skills can be active at once. PROMPT tools: [Tools::ActivateSkill, Tools::DeactivateSkill] ), workflow_management: Responsibility.new( prompt: <<~PROMPT, ────────────────────────────── WORKFLOW MANAGEMENT ────────────────────────────── Activate a workflow when the user starts a multi-step task that matches one. Read the returned content and use judgment to create goals — not a mechanical 1:1 mapping. Adapt to context: skip irrelevant steps, add extra steps for unfamiliar areas. Deactivate the workflow when it completes or the user shifts focus. Only one workflow active at a time — activating a new one replaces the previous. PROMPT tools: [Tools::ReadWorkflow, Tools::DeactivateWorkflow] ), goal_tracking: Responsibility.new( prompt: <<~PROMPT, ────────────────────────────── GOAL TRACKING ────────────────────────────── Create a root goal when the user starts a multi-step task. Break it into sub-goals as the plan becomes clear. Refine goal wording as understanding evolves. Mark goals complete when the agent finishes the work they describe. Completing a root goal cascades — all sub-goals are finished too. Never duplicate an existing goal — check the active goals list first. PROMPT tools: [Tools::SetGoal, Tools::UpdateGoal, Tools::FinishGoal] ) }.freeze
- BASE_PROMPT =
<<~PROMPT You manage context for the main agent — skills, goals, workflows, and session names. Watch the conversation and act when context needs updating. Communicate only through tool calls — never output text. PROMPT
- COMPLETION_PROMPT =
<<~PROMPT ────────────────────────────── COMPLETION ────────────────────────────── Always finish with everything_is_ready. If nothing needs attention, call it immediately. PROMPT
- PARENT_RESPONSIBILITIES =
Which responsibilities activate for each session type.
%i[session_naming skill_management workflow_management goal_tracking].freeze
- CHILD_RESPONSIBILITIES =
%i[sub_agent_naming skill_management workflow_management goal_tracking].freeze
Instance Method Summary collapse
-
#call ⇒ String?
Runs the analytical brain loop.
-
#initialize(session, client: nil) ⇒ Runner
constructor
A new instance of Runner.
Constructor Details
#initialize(session, client: nil) ⇒ Runner
Returns a new instance of Runner.
111 112 113 114 115 116 117 118 |
# File 'lib/analytical_brain/runner.rb', line 111 def initialize(session, client: nil) @session = session @client = client || LLM::Client.new( model: Anima::Settings.fast_model, max_tokens: Anima::Settings.analytical_brain_max_tokens, logger: AnalyticalBrain.logger ) end |
Instance Method Details
#call ⇒ String?
Runs the analytical brain loop. Builds context from the session’s recent messages, calls the LLM with the session-appropriate tool set, and executes any tool calls against the session.
Events emitted during tool execution are not persisted — the phantom session_id (nil) causes the global Persister to skip them.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/analytical_brain/runner.rb', line 129 def call = sid = @session.id if .empty? log.debug("session=#{sid} — no messages, skipping") return end system = build_system_prompt log.info("session=#{sid} — running (#{.size} messages)") log.debug("system prompt:\n#{system}") log.debug("user message:\n#{.first[:content]}") result = @client.chat_with_tools( , registry: build_registry, session_id: nil, system: system ) log.info("session=#{sid} — done: #{result.to_s.truncate(200)}") result end |