| 1 | //! siGit Code Cloud Sessions — named, resumable conversations. |
| 2 | |
| 3 | use crate::{ |
| 4 | client::Client, |
| 5 | error::Result, |
| 6 | models::{AppendedMessage, CloudSession}, |
| 7 | }; |
| 8 | |
| 9 | impl Client { |
| 10 | /// `GET /api/v1/sessions` — most recently updated first. |
| 11 | pub async fn sessions(&self) -> Result<Vec<CloudSession>> { |
| 12 | self.get("sessions").await |
| 13 | } |
| 14 | |
| 15 | /// `GET /api/v1/sessions/:id` — the session plus its full transcript. |
| 16 | pub async fn session(&self, id: i64) -> Result<CloudSession> { |
| 17 | self.get(&format!("sessions/{id}")).await |
| 18 | } |
| 19 | |
| 20 | /// `POST /api/v1/sessions` |
| 21 | pub async fn create_session( |
| 22 | &self, |
| 23 | title: Option<&str>, |
| 24 | model: Option<&str>, |
| 25 | ) -> Result<CloudSession> { |
| 26 | self.post("sessions", &session_body(title, model)).await |
| 27 | } |
| 28 | |
| 29 | /// `PATCH /api/v1/sessions/:id` |
| 30 | pub async fn update_session( |
| 31 | &self, |
| 32 | id: i64, |
| 33 | title: Option<&str>, |
| 34 | model: Option<&str>, |
| 35 | ) -> Result<CloudSession> { |
| 36 | self.patch(&format!("sessions/{id}"), &session_body(title, model)) |
| 37 | .await |
| 38 | } |
| 39 | |
| 40 | /// `DELETE /api/v1/sessions/:id` |
| 41 | pub async fn delete_session(&self, id: i64) -> Result<()> { |
| 42 | self.delete(&format!("sessions/{id}")).await |
| 43 | } |
| 44 | |
| 45 | /// `POST /api/v1/sessions/:id/messages` — append one message. |
| 46 | pub async fn append_message( |
| 47 | &self, |
| 48 | id: i64, |
| 49 | role: &str, |
| 50 | content: &str, |
| 51 | ) -> Result<AppendedMessage> { |
| 52 | let body = serde_json::json!({ "role": role, "content": content }); |
| 53 | self.post(&format!("sessions/{id}/messages"), &body).await |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | /// The server treats absent keys as "leave unchanged", so only send what the |
| 58 | /// caller actually supplied. |
| 59 | fn session_body(title: Option<&str>, model: Option<&str>) -> serde_json::Value { |
| 60 | let mut body = serde_json::Map::new(); |
| 61 | if let Some(title) = title { |
| 62 | body.insert("title".into(), title.into()); |
| 63 | } |
| 64 | if let Some(model) = model { |
| 65 | body.insert("model".into(), model.into()); |
| 66 | } |
| 67 | serde_json::Value::Object(body) |
| 68 | } |
| 69 | |
| 70 | #[cfg(test)] |
| 71 | mod tests { |
| 72 | use super::*; |
| 73 | |
| 74 | #[test] |
| 75 | fn omitted_fields_stay_out_of_the_update_body() { |
| 76 | let body = session_body(Some("Refactor auth"), None); |
| 77 | assert_eq!(body["title"], "Refactor auth"); |
| 78 | assert!(body.get("model").is_none()); |
| 79 | } |
| 80 | } |