objectiveai_sdk/cli/plugins/output.rs
1//! Wire format for the plugin output protocol.
2//!
3//! Plugins emit one [`Output`] JSON object per line on their stdout.
4//! The host parses each line and dispatches per variant: `command`
5//! is a request for the host to perform some action and (potentially)
6//! reply, `mcp` announces the URL of an MCP server the plugin just
7//! started, `error` is displayed, and anything that doesn't match
8//! those three lands in the untagged [`Output::Notification`]
9//! catch-all carrying the raw JSON value.
10
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13
14use super::Command;
15use crate::cli::Error;
16use crate::cli::command::plugins::run::Mcp;
17
18/// One line of plugin output. Untagged outer enum — deserialization
19/// tries each typed variant by its constant `type:"…"` discriminator
20/// in source order and falls through to [`Output::Notification`] as
21/// a catch-all carrying the raw JSON value.
22///
23/// [`Mcp`] is imported from
24/// [`crate::cli::command::plugins::run`] — this module does NOT
25/// re-export it; importers reach it by its canonical path.
26#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
27#[serde(untagged)]
28#[schemars(rename = "cli.plugins.Output")]
29pub enum Output {
30 #[schemars(title = "Command")]
31 Command(Command),
32 #[schemars(title = "Mcp")]
33 Mcp(Mcp),
34 #[schemars(title = "Error")]
35 Error(Error),
36 /// Final fallback — anything that didn't match a typed variant
37 /// lands here as an opaque JSON value. Hosts treat this as a
38 /// notification payload to forward upstream.
39 #[schemars(title = "Notification")]
40 Notification(serde_json::Value),
41}