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;