Class: VSM::Intelligence
- Inherits:
-
Object
- Object
- VSM::Intelligence
- Defined in:
- lib/vsm/roles/intelligence.rb
Overview
Orchestrates multi-turn LLM chat with native tool-calls:
-
Maintains neutral conversation history per session_id
-
Talks to a provider driver that yields :assistant_delta, :assistant_final, :tool_calls
-
Emits :tool_call to Operations, waits for ALL results, then continues
App authors can subclass and only customize:
- system_prompt(session_id) -> String
- offer_tools?(session_id, descriptor) -> true/false (filter tools)
Instance Attribute Summary collapse
-
#driver ⇒ Object
readonly
Returns the value of attribute driver.
Instance Method Summary collapse
- #handle(message, bus:) ⇒ Object
-
#initialize(driver: nil, system_prompt: nil) ⇒ Intelligence
constructor
A new instance of Intelligence.
- #observe(bus) ⇒ Object
-
#offer_tools?(session_id, descriptor) ⇒ Boolean
Override to filter tools the model may use (by descriptor).
-
#system_prompt(session_id) ⇒ Object
Override to compute a dynamic prompt per session.
Constructor Details
#initialize(driver: nil, system_prompt: nil) ⇒ Intelligence
Returns a new instance of Intelligence.
17 18 19 20 21 |
# File 'lib/vsm/roles/intelligence.rb', line 17 def initialize(driver: nil, system_prompt: nil) @driver = driver @system_prompt = system_prompt @sessions = Hash.new { |h,k| h[k] = new_session_state } end |
Instance Attribute Details
#driver ⇒ Object (readonly)
Returns the value of attribute driver.
15 16 17 |
# File 'lib/vsm/roles/intelligence.rb', line 15 def driver @driver end |
Instance Method Details
#handle(message, bus:) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/vsm/roles/intelligence.rb', line 25 def handle(, bus:, **) # If no driver is configured, the base implementation is inert. # Subclasses can override #handle to implement non-LLM behavior. return false if @driver.nil? case .kind when :user sid = .&.dig(:session_id) st = state(sid) st[:history] << { role: "user", content: .payload.to_s } invoke_model(sid, bus) true when :tool_result sid = .&.dig(:session_id) st = state(sid) # map id -> tool name if we learned it earlier (useful for Gemini) name = st[:tool_id_to_name][.corr_id] # Debug logging if ENV["VSM_DEBUG_STREAM"] == "1" $stderr.puts "Intelligence: Received tool_result for #{name}(#{.corr_id}): #{.payload.to_s.slice(0, 100)}" end st[:history] << { role: "tool_result", tool_call_id: .corr_id, name: name, content: .payload.to_s } st[:pending_tool_ids].delete(.corr_id) # Only continue once all tool results for this turn arrived: if st[:pending_tool_ids].empty? # Re-enter model for the same turn with tool results in history: invoke_model(sid, bus) end true else false end end |
#observe(bus) ⇒ Object
23 |
# File 'lib/vsm/roles/intelligence.rb', line 23 def observe(bus); end |
#offer_tools?(session_id, descriptor) ⇒ Boolean
Override to filter tools the model may use (by descriptor)
70 71 72 |
# File 'lib/vsm/roles/intelligence.rb', line 70 def offer_tools?(session_id, descriptor) true end |
#system_prompt(session_id) ⇒ Object
Override to compute a dynamic prompt per session
65 66 67 |
# File 'lib/vsm/roles/intelligence.rb', line 65 def system_prompt(session_id) @system_prompt end |