2026-02-16 16:24:21 +00:00
|
|
|
use crate::http::context::{AppContext, OpenApiResult, bad_request};
|
|
|
|
|
use crate::llm::chat;
|
2026-02-16 16:50:50 +00:00
|
|
|
use poem_openapi::{OpenApi, Tags, payload::Json};
|
2026-02-16 16:35:25 +00:00
|
|
|
use std::sync::Arc;
|
2026-02-16 16:24:21 +00:00
|
|
|
|
2026-02-16 16:50:50 +00:00
|
|
|
#[derive(Tags)]
|
|
|
|
|
enum ChatTags {
|
|
|
|
|
Chat,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-16 16:35:25 +00:00
|
|
|
pub struct ChatApi {
|
|
|
|
|
pub ctx: Arc<AppContext>,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-16 16:50:50 +00:00
|
|
|
#[OpenApi(tag = "ChatTags::Chat")]
|
2026-02-16 16:35:25 +00:00
|
|
|
impl ChatApi {
|
2026-02-16 16:50:50 +00:00
|
|
|
/// Cancel the currently running chat stream, if any.
|
|
|
|
|
///
|
|
|
|
|
/// Returns `true` once the cancellation signal is issued.
|
2026-02-16 16:35:25 +00:00
|
|
|
#[oai(path = "/chat/cancel", method = "post")]
|
|
|
|
|
async fn cancel_chat(&self) -> OpenApiResult<Json<bool>> {
|
|
|
|
|
chat::cancel_chat(&self.ctx.state).map_err(bad_request)?;
|
|
|
|
|
Ok(Json(true))
|
|
|
|
|
}
|
2026-02-16 16:24:21 +00:00
|
|
|
}
|
2026-02-23 22:02:55 +00:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
use tempfile::TempDir;
|
|
|
|
|
|
|
|
|
|
fn test_api(dir: &TempDir) -> ChatApi {
|
|
|
|
|
ChatApi {
|
|
|
|
|
ctx: Arc::new(AppContext::new_test(dir.path().to_path_buf())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn cancel_chat_returns_true() {
|
|
|
|
|
let dir = TempDir::new().unwrap();
|
|
|
|
|
let api = test_api(&dir);
|
|
|
|
|
let result = api.cancel_chat().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
assert!(result.unwrap().0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn cancel_chat_sends_cancel_signal() {
|
|
|
|
|
let dir = TempDir::new().unwrap();
|
|
|
|
|
let api = test_api(&dir);
|
|
|
|
|
let mut cancel_rx = api.ctx.state.cancel_rx.clone();
|
|
|
|
|
cancel_rx.borrow_and_update();
|
|
|
|
|
|
|
|
|
|
api.cancel_chat().await.unwrap();
|
|
|
|
|
|
|
|
|
|
assert!(*cancel_rx.borrow());
|
|
|
|
|
}
|
|
|
|
|
}
|