use async_trait::async_trait;
use everruns_core::error::{AgentLoopError, Result};
use everruns_core::platform_store::PlatformMessage;
use everruns_core::session::Session;
use everruns_core::typed_id::{AgentId, HarnessId, SessionId};
use everruns_local::LocalSessionRunner;
use tokio::sync::mpsc;
pub type WakeSender = mpsc::UnboundedSender<String>;
pub type WakeReceiver = mpsc::UnboundedReceiver<String>;
pub struct WakeRunner {
wake_tx: WakeSender,
}
impl WakeRunner {
pub fn new(wake_tx: WakeSender) -> Self {
Self { wake_tx }
}
}
pub fn frame_wake_prompt(message: &str) -> String {
format!(
"[automatic] A background task you started has finished:\n\n{message}\n\nThis is not a \
user message. Read the run's result if useful (its `result_path`/`log_path` are session \
files you can read), then continue the work it was for or report the result."
)
}
#[async_trait]
impl LocalSessionRunner for WakeRunner {
async fn send_message(&self, _session_id: SessionId, content: &str) -> Result<()> {
let _ = self.wake_tx.send(content.to_string());
Ok(())
}
async fn create_session(
&self,
_harness_id: HarnessId,
_agent_id: Option<AgentId>,
_title: Option<&str>,
_locale: Option<&str>,
_parent_session_id: Option<SessionId>,
) -> Result<Session> {
Err(unsupported("create_session"))
}
async fn list_sessions(
&self,
_limit: Option<usize>,
_agent_id: Option<AgentId>,
) -> Result<Vec<Session>> {
Ok(Vec::new())
}
async fn get_session(&self, _session_id: SessionId) -> Result<Option<Session>> {
Ok(None)
}
async fn get_messages(
&self,
_session_id: SessionId,
_limit: Option<usize>,
) -> Result<Vec<PlatformMessage>> {
Ok(Vec::new())
}
async fn get_session_status(&self, _session_id: SessionId) -> Result<Option<String>> {
Ok(None)
}
}
fn unsupported(op: &str) -> AgentLoopError {
AgentLoopError::tool(format!(
"the local wake runner does not support '{op}' (background completions only)"
))
}