pub struct Question {Show 14 fields
pub schema: u32,
pub id: String,
pub run: String,
pub node: String,
pub seat: String,
pub summary: String,
pub detail: String,
pub choices: Vec<String>,
pub panel: bool,
pub assets: Vec<String>,
pub status: QuestionStatus,
pub asked_at: Timestamp,
pub answered_at: Option<Timestamp>,
pub answer: Option<Answer>,
}Expand description
One decision magi will not take on the owner’s behalf.
Fields§
§schema: u32On-disk format version.
id: StringQuestion id, e.g. 20260902-231501-ab12. Same shape as a run’s and a
task’s, so the operator can paste any of them at any prefix argument.
run: StringRun that is parked behind this question.
node: StringGraph node the asking agent was working in, e.g. implement.
seat: StringSeat that asked, e.g. impl-A. Recorded because “which agent needs
this” decides whether the answer unblocks one candidate or all of them.
summary: StringOne line: the question itself. This is what a notification carries and what the phone shows above the answer controls.
detail: StringThe reasoning behind the question, as markdown. May be long, may be empty. Rendered as text nodes by the UI, never as markup.
choices: Vec<String>The admissible answers. Empty means free text - that one condition
is the whole difference between the two kinds of question, on disk, in
the UI, and in Question::answer’s validation.
panel: boolDoes this question have an agent-authored HTML panel beside it?
Serialised with a default so a question written by an older magi - or
by hand - still deserialises rather than failing the whole store, which
under Questions::list’s skip-unreadable rule would quietly hide the
open question the operator was looking for.
assets: Vec<String>Files copied in beside the panel’s html, by base name, sorted.
The list exists so a reader knows what a panel is made of without
walking the directory, and every entry satisfies valid_asset_name.
Sorted because it is compared - a question re-asked with the same
assets in a different argument order is not a different question.
status: QuestionStatusCurrent state.
asked_at: TimestampWhen the agent asked.
answered_at: Option<Timestamp>When the owner answered, if they did.
answer: Option<Answer>What they said.
Implementations§
Source§impl Question
impl Question
Sourcepub fn new(
run: String,
node: String,
seat: String,
summary: String,
detail: String,
choices: Vec<String>,
) -> Self
pub fn new( run: String, node: String, seat: String, summary: String, detail: String, choices: Vec<String>, ) -> Self
Ask something. Persist it with Questions::put, or hand it to
ask_and_wait, which files it and waits.
Sourcepub fn short(&self) -> &str
pub fn short(&self) -> &str
Short form used in reports and on the phone, matching a run’s short id.
Sourcepub fn answer(&mut self, answer: Answer) -> Result<()>
pub fn answer(&mut self, answer: Answer) -> Result<()>
Record an answer. Rejects a choice the question does not offer, free text on a multiple-choice question, an empty answer, and a second answer.
Every rejection here is a case where accepting would put a fabrication in front of an agent as if the owner had said it. The messages are distinct because the caller is a web handler that shows them verbatim, and “that is not one of the choices” and “this question is multiple choice” are different mistakes with different fixes.
Sourcepub fn abandon(&mut self, why: impl Into<String>)
pub fn abandon(&mut self, why: impl Into<String>)
Give up on an answer, keeping the record of what was asked.
An answered question is left alone, which matters at exactly one moment: the owner answering in the same second the wait’s deadline passes. The answer is the thing worth keeping there, and it has already been written by another process.
The reason is appended to Question::detail because the on-disk shape
is a contract with the front end and has no field of its own for it -
and “asked at 3am, nobody home for a day” belongs with the question, not
only in a log the operator will never open.
Sourcepub fn resolution(&self) -> Option<String>
pub fn resolution(&self) -> Option<String>
The answer as the asking agent should read it.
One string for both kinds of question: the agent’s prompt says “the
owner answered:”, and a chosen option and a typed sentence are the same
thing at that point. None while the question is open or abandoned, so
a caller cannot mistake silence for a decision.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Question
impl<'de> Deserialize<'de> for Question
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Question
impl StructuralPartialEq for Question
Auto Trait Implementations§
impl Freeze for Question
impl RefUnwindSafe for Question
impl Send for Question
impl Sync for Question
impl Unpin for Question
impl UnsafeUnpin for Question
impl UnwindSafe for Question
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more