Class: Rubino::Interaction::Lifecycle
- Inherits:
-
Object
- Object
- Rubino::Interaction::Lifecycle
- Defined in:
- lib/rubino/interaction/lifecycle.rb
Overview
Orchestrates the full lifecycle of a single user interaction. Coordinates all phases from input to final response and post-turn jobs.
Instance Method Summary collapse
-
#execute(input, image_paths: [], input_queue: nil, paste_expansions: []) ⇒ Object
Executes the full interaction lifecycle for a user input.
-
#initialize(session:, event_bus:, ui:, config:, ignore_rules: false, agent_definition: nil, cancel_token: nil, model_override: nil, provider_override: nil, max_tool_iterations: nil) ⇒ Lifecycle
constructor
A new instance of Lifecycle.
Constructor Details
#initialize(session:, event_bus:, ui:, config:, ignore_rules: false, agent_definition: nil, cancel_token: nil, model_override: nil, provider_override: nil, max_tool_iterations: nil) ⇒ Lifecycle
Returns a new instance of Lifecycle.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/rubino/interaction/lifecycle.rb', line 8 def initialize(session:, event_bus:, ui:, config:, ignore_rules: false, agent_definition: nil, cancel_token: nil, model_override: nil, provider_override: nil, max_tool_iterations: nil) @session = session @event_bus = event_bus @ui = ui @config = config @ignore_rules = ignore_rules @agent_definition = agent_definition @cancel_token = cancel_token @model_override = model_override @provider_override = provider_override # Explicit per-run cap from `--max-turns` (Runner → here → IterationBudget). # nil ⇒ use the configured agent_max_tool_iterations (#141). @max_tool_iterations = max_tool_iterations @state = State.new @session_repo = Session::Repository.new @message_store = Session::Store.new end |
Instance Method Details
#execute(input, image_paths: [], input_queue: nil, paste_expansions: []) ⇒ Object
Executes the full interaction lifecycle for a user input. image_paths are vision-capable attachments routed natively to the primary model (ruby_llm ‘with:` slot); only consumed on the first iteration of the inner agent loop. Subsequent iterations carry tool results, not user input, and don’t re-attach the images. input_queue is the optional steering hand-off (Interaction::InputQueue) for mid-turn injection: when given, the inner agent loop drains any text the user typed while it was working and folds it into the turn at a safe iteration boundary. Nil for the API/server path and for nested SUBAGENT runs, which stay isolated — no user injection, exactly as before.
39 40 41 42 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/rubino/interaction/lifecycle.rb', line 39 def execute(input, image_paths: [], input_queue: nil, paste_expansions: []) @event_bus.emit(Events::INTERACTION_STARTED, input: input) @state.transition_to!(:receiving_input, event_bus: @event_bus) # 1. Persist user message @state.transition_to!(:loading_session, event_bus: @event_bus) (input, paste_expansions: paste_expansions) # 2. Load memory (if enabled) @state.transition_to!(:loading_memory, event_bus: @event_bus) memory_context = load_memory(input) # 3. Build prompt/context @state.transition_to!(:building_context, event_bus: @event_bus) = (input, memory_context) tools = load_tools # 4. Check token budget @state.transition_to!(:checking_budget, event_bus: @event_bus) = check_and_compact() # 5. Run agent loop @state.transition_to!(:calling_model, event_bus: @event_bus) response = run_agent_loop(, tools, image_paths: image_paths, input_queue: input_queue) # 6. Persist session state @state.transition_to!(:persisting_session, event_bus: @event_bus) update_session_state # 7. Enqueue post-turn jobs @state.transition_to!(:enqueueing_jobs, event_bus: @event_bus) enqueue_post_turn_jobs # 8. Finish # Carry the final assistant text as the terminal event's authoritative # output, regardless of streaming mode. Streaming consumers also receive # it incrementally via MODEL_STREAM (message.delta), but the # non-streaming path emits no deltas — so without this, a completed run # would terminate with no final text for clients to display. This makes # run.completed the single source of truth for the answer. @state.transition_to!(:finished, event_bus: @event_bus) @event_bus.emit(Events::INTERACTION_FINISHED, output: response.to_s) response rescue StandardError => e @state.transition_to!(:failed, event_bus: @event_bus) @event_bus.emit(Events::INTERACTION_FAILED, error: e.) raise end |