lash_remote_protocol/
turn_input.rs1use std::collections::HashMap;
5
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9use crate::llm::RemoteAttachmentSource;
10use crate::prompt::RemotePromptLayer;
11use crate::registry_errors::{RemoteProtocolError, require_non_empty};
12use crate::tools::RemoteToolGrant;
13use crate::{REMOTE_PROTOCOL_VERSION, ensure_protocol_version};
14
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
16pub struct RemoteProtocolTurnOptions {
17 #[serde(default = "empty_protocol_turn_payload")]
18 pub payload: serde_json::Value,
19}
20
21fn empty_protocol_turn_payload() -> serde_json::Value {
22 serde_json::Value::Object(serde_json::Map::new())
23}
24
25impl Default for RemoteProtocolTurnOptions {
26 fn default() -> Self {
27 Self {
28 payload: empty_protocol_turn_payload(),
29 }
30 }
31}
32
33impl RemoteProtocolTurnOptions {
34 pub fn empty() -> Self {
35 Self::default()
36 }
37
38 pub fn is_empty(&self) -> bool {
39 match &self.payload {
40 serde_json::Value::Object(map) => map.is_empty(),
41 _ => false,
42 }
43 }
44}
45
46#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
47pub struct RemoteTurnInput {
48 pub protocol_version: u32,
49 #[serde(default)]
50 pub items: Vec<RemoteInputItem>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub protocol_turn_options: Option<RemoteProtocolTurnOptions>,
53 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub trace_turn_id: Option<String>,
55 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub prompt_layer: Option<RemotePromptLayer>,
57}
58
59impl RemoteTurnInput {
60 pub fn text(text: impl Into<String>) -> Self {
61 Self {
62 protocol_version: REMOTE_PROTOCOL_VERSION,
63 items: vec![RemoteInputItem::Text { text: text.into() }],
64 protocol_turn_options: None,
65 trace_turn_id: None,
66 prompt_layer: None,
67 }
68 }
69
70 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
71 ensure_protocol_version(self.protocol_version)?;
72 for (index, item) in self.items.iter().enumerate() {
73 if let RemoteInputItem::Attachment { source } = item {
74 source.validate(index)?;
75 }
76 }
77 Ok(())
78 }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
82#[serde(tag = "type", rename_all = "snake_case")]
83pub enum RemoteInputItem {
84 Text { text: String },
85 Attachment { source: RemoteAttachmentSource },
86}
87
88#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
89pub struct RemoteTurnRequest {
90 pub protocol_version: u32,
91 pub session_id: String,
92 pub turn_id: String,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
94 pub idempotency_key: Option<String>,
95 pub input: RemoteTurnInput,
96 #[serde(default, skip_serializing_if = "Vec::is_empty")]
97 pub tool_grants: Vec<RemoteToolGrant>,
98 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
99 pub metadata: HashMap<String, serde_json::Value>,
100}
101
102impl RemoteTurnRequest {
103 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
104 ensure_protocol_version(self.protocol_version)?;
105 require_non_empty("RemoteTurnRequest", "session_id", &self.session_id)?;
106 require_non_empty("RemoteTurnRequest", "turn_id", &self.turn_id)?;
107 if self.input.protocol_version != self.protocol_version {
108 return Err(RemoteProtocolError::MismatchedNestedProtocolVersion {
109 parent: "RemoteTurnRequest",
110 child: "input",
111 parent_version: self.protocol_version,
112 child_version: self.input.protocol_version,
113 });
114 }
115 self.input.validate()?;
116 RemoteToolGrant::validate_all(&self.tool_grants)?;
117 Ok(())
118 }
119}