aboutsummaryrefslogtreecommitdiff
path: root/src/protocol/endpoint.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/endpoint.rs')
-rw-r--r--src/protocol/endpoint.rs57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/protocol/endpoint.rs b/src/protocol/endpoint.rs
index a70ef568..640e594e 100644
--- a/src/protocol/endpoint.rs
+++ b/src/protocol/endpoint.rs
@@ -27,6 +27,8 @@ pub const PRESENTATION_EFFECTS_READY_KIND: &str = "endpoint.presentation.ready.v
pub const HEALTH_CHECK_CAPABILITY: &str = "health_check";
pub const HEALTH_PING_KIND: &str = "endpoint.health.ping.v1";
pub const HEALTH_PONG_KIND: &str = "endpoint.health.pong.v1";
+pub const AGENT_VIEW_PROJECTION_CAPABILITY: &str = "agent_view_projection";
+pub const AGENT_VIEW_PROJECTION_KIND: &str = "endpoint.agent-view.v1";
fn default_true() -> bool {
true
@@ -60,6 +62,16 @@ pub struct EndpointHandshakeError {
pub message: String,
}
+/// Optional companion to a V1 snapshot. The view payload is intentionally opaque to this
+/// stable envelope so clients can ignore view language additions they do not understand.
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct EndpointAgentViewProjection {
+ pub boot_id: String,
+ pub revision: u64,
+ #[serde(default)]
+ pub view: Option<serde_json::Value>,
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct EndpointServerWelcome {
pub generation: u32,
@@ -83,6 +95,22 @@ pub fn snapshot_message(snapshot: &ClientShellSnapshot) -> serde_json::Result<Se
})
}
+pub fn agent_view_projection_message(
+ boot_id: &str,
+ revision: u64,
+ view: Option<&crate::api::schema::AgentViewSetParams>,
+) -> serde_json::Result<ServerMessage> {
+ let projection = EndpointAgentViewProjection {
+ boot_id: boot_id.to_owned(),
+ revision,
+ view: view.map(serde_json::to_value).transpose()?,
+ };
+ Ok(ServerMessage::EndpointControl {
+ kind: AGENT_VIEW_PROJECTION_KIND.into(),
+ data: serde_json::to_string(&projection)?,
+ })
+}
+
impl EndpointClientHello {
pub fn supports_required_codecs(&self) -> bool {
self.snapshot_codecs
@@ -114,6 +142,7 @@ impl EndpointServerWelcome {
SURFACE_INTEREST_CAPABILITY.into(),
PRESENTATION_EFFECTS_FENCE_CAPABILITY.into(),
HEALTH_CHECK_CAPABILITY.into(),
+ AGENT_VIEW_PROJECTION_CAPABILITY.into(),
],
error: None,
}
@@ -244,6 +273,33 @@ mod tests {
}
#[test]
+ fn agent_view_projection_is_an_optional_revision_bound_control() {
+ let view = crate::api::schema::AgentViewSetParams {
+ source: "example.views".into(),
+ label: Some("focus".into()),
+ filter: None,
+ sort: Vec::new(),
+ };
+ let ServerMessage::EndpointControl { kind, data } =
+ agent_view_projection_message("boot", 7, Some(&view)).unwrap()
+ else {
+ panic!("projection should use endpoint control");
+ };
+ assert_eq!(kind, AGENT_VIEW_PROJECTION_KIND);
+ let projection: EndpointAgentViewProjection = serde_json::from_str(&data).unwrap();
+ assert_eq!(projection.boot_id, "boot");
+ assert_eq!(projection.revision, 7);
+ assert_eq!(
+ projection
+ .view
+ .map(serde_json::from_value)
+ .transpose()
+ .unwrap(),
+ Some(view)
+ );
+ }
+
+ #[test]
fn snapshot_json_tolerates_future_fields_and_command_actions() {
let mut snapshot = match snapshot_message(&snapshot()).unwrap() {
ServerMessage::EndpointControl { data, .. } => {
@@ -284,6 +340,7 @@ mod tests {
SURFACE_INTEREST_CAPABILITY.to_string(),
PRESENTATION_EFFECTS_FENCE_CAPABILITY.to_string(),
HEALTH_CHECK_CAPABILITY.to_string(),
+ AGENT_VIEW_PROJECTION_CAPABILITY.to_string(),
]
);
}