Class: Rubino::Commands::Handlers::Agents
- Inherits:
-
Object
- Object
- Rubino::Commands::Handlers::Agents
- Includes:
- UI::ProbeWaitIndicator
- Defined in:
- lib/rubino/commands/handlers/agents.rb
Overview
The ‘/agents` (alias `/tasks`) drill-in surface and the `/reply` answer path, extracted from Commands::Executor (batch B).
The “see what other agents do” surface. Lists background subagents from the BackgroundTasks registry (the async ‘task` substrate), drills into a single one’s result/error, steers/probes/stops a running one, and routes a human /reply back down to a blocked child.
/agents → list
/agents <id> → drill-in (result / error / status)
/agents <id> --stop → cancel a running subagent
/agents <id> steer "…" → fire-and-forget note into the child's context
/agents <id> probe "…" → ephemeral read-only peek
/reply <id> <answer> → answer a child blocked on a human/parent ask
Constant Summary collapse
- APPROVAL_ASK_ATTEMPTS =
How many times the parked-child approval prompt re-renders after an empty/aborted read (#144) before giving up and leaving the child parked.
3
Instance Method Summary collapse
- #handle_agents(arguments) ⇒ Object
-
#handle_reply(arguments) ⇒ Object
child->parent ASK_PARENT answer: /reply <id> <answer>.
-
#initialize(ui:) ⇒ Agents
constructor
A new instance of Agents.
Methods included from UI::ProbeWaitIndicator
#probe_thinking_finished, #probe_thinking_started
Constructor Details
#initialize(ui:) ⇒ Agents
Returns a new instance of Agents.
30 31 32 |
# File 'lib/rubino/commands/handlers/agents.rb', line 30 def initialize(ui:) @ui = ui end |
Instance Method Details
#handle_agents(arguments) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/rubino/commands/handlers/agents.rb', line 34 def handle_agents(arguments) args = arguments.to_s.strip if args.empty? show_agents_list return end tokens = args.split(/\s+/) stop = tokens.delete("--stop") ? true : false id = tokens.shift if id.nil? || id.empty? show_agents_list elsif stop stop_agent(id) elsif tokens.first == "steer" steer_agent(id, dequote(tokens[1..].join(" "))) elsif tokens.first == "probe" probe_agent(id, dequote(tokens[1..].join(" "))) else show_agent_detail(id) end end |
#handle_reply(arguments) ⇒ Object
child->parent ASK_PARENT answer: /reply <id> <answer>. Resolves the child’s ask gate (Run::ApprovalGate#decide) so a BLOCKING ask unwinds with the answer as its tool result, and ALSO pushes the answer onto the child’s steer queue so a NON-BLOCKING ask folds it in at its next turn boundary. Either way the answer PERSISTS in the child’s context. With no inline answer, falls back to an interactive prompt (the ◆ takeover, like the approval menu). Clears the blocked state and unblocks the tree.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/rubino/commands/handlers/agents.rb', line 66 def handle_reply(arguments) tokens = arguments.to_s.strip.split(/\s+/) id = tokens.shift if id.nil? || id.empty? show_blocked_agents return end # /reply is UNSCOPED: the human is the ultimate supervisor and may answer # ANY blocked node — one waiting on the human (:blocked_on_human) OR one # waiting on its agent-parent (:blocked_on_parent), if the human chooses # to step in. entry = Tools::BackgroundTasks.instance.find(id) if entry.nil? || !%i[blocked_on_human blocked_on_parent].include?(entry.status) @ui.error("#{id} is not waiting on you.") return end answer = dequote(tokens.join(" ")) answer = prompt_reply_answer(entry) if answer.to_s.strip.empty? if answer.to_s.strip.empty? @ui.info("No answer given — #{id} is still waiting.") return end deliver_reply(entry, answer) end |