ask_operator: multi-select + free-text fallback

ask_operator now accepts a multi: bool. when true and options is
non-empty, the dashboard renders the choices as checkboxes — operator
picks any subset, answer comes back as a ', '-joined string. when
false (default), options are radio buttons.

independent of multi, a free-text input ('or type your own…') is
always rendered alongside options so the operator is never trapped
by an incomplete list. submit merges checked options + free text into
the single 'answer' field.

schema migration: operator_questions grows a multi INTEGER column
with a one-shot ALTER TABLE on open. backward compatible — old rows
default to 0 (not multi).

prompt + mcp tool description updated; existing dashboard css for
.qform was rewritten around the new vertical layout.
This commit is contained in:
müde 2026-05-15 19:52:44 +02:00
parent c337cc06f8
commit 8344dd9ab7
7 changed files with 130 additions and 35 deletions

View file

@ -289,13 +289,22 @@ pub enum ManagerRequest {
agent: String,
commit_ref: String,
},
/// Ask the operator a question. The host-side handler blocks until the
/// operator answers via the dashboard; the answer is then returned as the
/// response. `options` is advisory: an empty list means free-text.
/// Ask the operator a question. Returns immediately with the queued
/// question id; the operator's answer arrives later as a
/// `HelperEvent::OperatorAnswered` in the manager inbox.
///
/// - `options` is advisory: empty = free-text only; non-empty = the
/// dashboard renders the choices alongside a free-text fallback
/// ("Other…") so the operator is never trapped.
/// - `multi=true` lets the operator pick multiple options (rendered
/// as checkboxes). The answer is returned as a single string with
/// selections joined by ", ".
AskOperator {
question: String,
#[serde(default)]
options: Vec<String>,
#[serde(default)]
multi: bool,
},
}