Skip to main content

objectiveai_cli_sdk/output/
mod.rs

1//! Structured JSON Lines output for `objectiveai-cli`.
2//!
3//! Every line `objectiveai-cli` writes to stdout is one [`Output`] JSON
4//! object. There are two top-level shapes, discriminated by `"type"`:
5//!
6//! - `error` — a failure or advisory ([`Error`]).
7//! - `notification` — a typed payload `T` chosen by the consumer (the
8//!   CLI defines its own notification enum and parameterizes
9//!   `Output<T>` over it).
10//!
11//! `T` is flattened into the same JSON object as the `"type"` tag via
12//! serde's internal tagging, so `T` should be a struct or an
13//! internally-tagged enum.
14
15mod error;
16mod handle;
17pub mod notification;
18
19pub use error::*;
20pub use handle::*;
21pub use notification::*;
22
23use serde::{Deserialize, Serialize};
24
25/// A single line of CLI output.
26#[derive(Serialize, Deserialize, Debug, Clone)]
27#[serde(tag = "type", rename_all = "snake_case")]
28pub enum Output<T> {
29    Error(Error),
30    /// Wraps `T` in [`Notification`] so its fields end up under a
31    /// nested `value` key — protects against `T` carrying its own
32    /// `"type"` field colliding with this enum's discriminator.
33    Notification(Notification<T>),
34    /// Stream-start marker. Wire: `{"type":"begin"}`.
35    Begin,
36    /// Stream-end marker. Wire: `{"type":"end"}`.
37    End,
38}
39
40impl<T: Serialize> Output<T> {
41    /// Emit this output via `handle`. Equivalent to
42    /// `handle.emit(self).await`; see [`Handle::emit`] for the routing
43    /// details.
44    pub async fn emit(&self, handle: &Handle) {
45        handle.emit(self).await
46    }
47}
48
49#[cfg(test)]
50mod tests;