# /agent/schema

> The server sends nothing; the proxy sends exactly one answer, the JSON Schema of the agent value or an error, and closes the connection.

Canonical: https://provider.diverge.network/2.3.0/proxy/agent/schema/
Specification revision: 2.3.0

The server opens `/agent/schema` and sends no message. The proxy sends
exactly one message and closes the connection. In the message, a
first byte of `0` is followed by a JSON Schema; a first byte of `1`
is followed by an error as JSON. A path that the proxy or the server closes cleanly with no message
before the close states that the schema was not served.

The answer is defined by
`diverge-provider-sdk/src/shared/containers/agent_schema/response/frame.rs`:

```rust
//! What an agent schema channel answers.

use std::fmt;

use serde_json::Value;

use crate::decode::Decode;
use crate::encode::{Encode, Writer};
use crate::shared::error::Error;

/// The agent's schema, or the news that there is none.
///
/// A payload leads with one byte saying which — `0` for
/// [`AgentSchema`](Self::AgentSchema), `1` for [`Error`](Self::Error)
/// — and the
/// rest is that variant's own JSON. One frame is all there is, and the
/// channel finishes after it.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame {
    /// The JSON Schema of the
    /// [`agent`](crate::endpoints::containers::agents::run::client::request::Frame::agent)
    /// value, as the image states it. Tag `0`.
    ///
    /// A [`Value`] rather than a typed schema, because a schema is a
    /// document in its own vocabulary and this crate has no business
    /// restating it.
    AgentSchema(Value),
    /// A failure. Tag `1`.
    ///
    /// The image has no schema to give, or the container could not be
    /// asked. See [`shared::error::Error`](crate::shared::error::Error)
    /// for why it says so little.
    Error(Error),
}

/// Tag for [`Frame::AgentSchema`]. Public, so a relay that carries
/// the schema's JSON without reading it can frame it.
pub const AGENT_SCHEMA: u8 = 0;

/// Tag for [`Frame::Error`].
const ERROR: u8 = 1;

impl Encode for Frame {
    /// The ordinary JSON failure, from either half.
    type Error = serde_json::Error;

    // Spelled out rather than `Self::Error`: this enum has a variant
    // called `Error`, so the associated type is ambiguous by that name.
    fn encode(&self, out: &mut Writer<'_>) -> Result<(), serde_json::Error> {
        match self {
            Frame::AgentSchema(schema) => {
                out.extend_from_slice(&[AGENT_SCHEMA]);
                serde_json::to_writer(out, schema)
            }
            Frame::Error(error) => {
                out.extend_from_slice(&[ERROR]);
                error.encode(out)
            }
        }
    }
}

impl Decode<'_> for Frame {
    /// Four ways to fail, and each names which half failed.
    type Error = FrameError;

    // Spelled out for the same reason as `encode` above.
    fn decode(bytes: &[u8]) -> Result<Self, FrameError> {
        let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
        match *tag {
            AGENT_SCHEMA => serde_json::from_slice(rest)
                .map(Frame::AgentSchema)
                .map_err(FrameError::AgentSchema),
            ERROR => {
                Error::decode(rest).map(Frame::Error).map_err(FrameError::Error)
            }
            tag => Err(FrameError::UnknownTag(tag)),
        }
    }
}

/// An agent schema answer that could not be read.
#[derive(Debug)]
pub enum FrameError {
    /// No bytes at all, so not even a tag.
    Empty,
    /// A tag that is neither of this frame's two.
    UnknownTag(u8),
    /// The schema did not parse.
    AgentSchema(serde_json::Error),
    /// The error did not parse.
    Error(serde_json::Error),
}

impl fmt::Display for FrameError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FrameError::Empty => f.write_str("agent schema answer frame is empty"),
            FrameError::UnknownTag(tag) => {
                write!(f, "unknown agent schema answer frame tag {tag}")
            }
            FrameError::AgentSchema(error) => {
                write!(f, "agent schema did not parse: {error}")
            }
            FrameError::Error(error) => {
                write!(f, "agent schema error did not parse: {error}")
            }
        }
    }
}

impl std::error::Error for FrameError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            FrameError::AgentSchema(error) | FrameError::Error(error) => Some(error),
            FrameError::Empty | FrameError::UnknownTag(_) => None,
        }
    }
}
```
