| 1 | //! The flattened result of one inference turn. |
| 2 | |
| 3 | use serde::{Deserialize, Serialize}; |
| 4 | |
| 5 | /// The outcome of a single [`Ed::send`](crate::Ed::send), in one shape whether |
| 6 | /// it succeeded or failed. |
| 7 | /// |
| 8 | /// Inference returns `Result<InferenceResult, InferenceError>`, but a frontend |
| 9 | /// receiving this over an event boundary wants a single payload it can render |
| 10 | /// either way. Every application built on `onde` was flattening it the same |
| 11 | /// way, so Ed does it once. `reply` and `error` are mutually exclusive: |
| 12 | /// exactly one is `Some`. |
| 13 | #[derive(Debug, Clone, Serialize, Deserialize)] |
| 14 | pub struct ChatReply { |
| 15 | /// The assistant's text, or `None` if inference failed. |
| 16 | pub reply: Option<String>, |
| 17 | /// Human-readable generation time (e.g. `"1.4s"`), or `None` on failure. |
| 18 | pub duration: Option<String>, |
| 19 | /// Why inference failed, or `None` on success. |
| 20 | pub error: Option<String>, |
| 21 | } |
| 22 | |
| 23 | impl ChatReply { |
| 24 | pub(crate) fn ok(reply: String, duration: String) -> Self { |
| 25 | Self { |
| 26 | reply: Some(reply), |
| 27 | duration: Some(duration), |
| 28 | error: None, |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | pub(crate) fn failed(error: impl std::fmt::Display) -> Self { |
| 33 | Self { |
| 34 | reply: None, |
| 35 | duration: None, |
| 36 | error: Some(error.to_string()), |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | /// Whether this turn produced an answer. |
| 41 | pub fn is_ok(&self) -> bool { |
| 42 | self.reply.is_some() |
| 43 | } |
| 44 | } |