Skip to main content

crabtalk_runtime/
host.rs

1//! Host — trait for server-specific tool dispatch.
2//!
3//! The runtime crate defines this trait. The daemon implements it to provide
4//! `ask_user`, `delegate`, and per-conversation CWD resolution. Embedded users
5//! get [`NoHost`] with no-op defaults.
6
7use std::path::PathBuf;
8
9/// Trait for server-specific tool dispatch that the runtime cannot handle locally.
10pub trait Host: Send + Sync + Clone {
11    /// Handle `ask_user` — block until user replies.
12    fn dispatch_ask_user(
13        &self,
14        args: &str,
15        conversation_id: Option<u64>,
16    ) -> impl std::future::Future<Output = String> + Send {
17        let _ = (args, conversation_id);
18        async { "ask_user is not available in this runtime mode".to_owned() }
19    }
20
21    /// Handle `delegate` — spawn sub-agent tasks.
22    fn dispatch_delegate(
23        &self,
24        args: &str,
25        agent: &str,
26    ) -> impl std::future::Future<Output = String> + Send {
27        let _ = (args, agent);
28        async { "delegate is not available in this runtime mode".to_owned() }
29    }
30
31    /// Resolve the working directory for a conversation.
32    /// Returns `None` to fall back to the runtime's base cwd.
33    fn conversation_cwd(&self, _conversation_id: u64) -> Option<PathBuf> {
34        None
35    }
36
37    /// Called when an agent event occurs. The daemon uses this to broadcast
38    /// protobuf events to console subscribers. Default: no-op.
39    fn on_agent_event(&self, _agent: &str, _conversation_id: u64, _event: &wcore::AgentEvent) {}
40
41    /// Deliver a user reply to a pending `ask_user` tool call.
42    /// Returns `true` if a pending ask was found and resolved.
43    fn reply_to_ask(
44        &self,
45        _session: u64,
46        _content: String,
47    ) -> impl std::future::Future<Output = anyhow::Result<bool>> + Send {
48        async { Ok(false) }
49    }
50
51    /// Set the working directory override for a conversation.
52    fn set_conversation_cwd(
53        &self,
54        _conversation: u64,
55        _cwd: PathBuf,
56    ) -> impl std::future::Future<Output = ()> + Send {
57        async {}
58    }
59
60    /// Clear all per-conversation state (pending asks, CWD overrides).
61    fn clear_conversation_state(
62        &self,
63        _conversation: u64,
64    ) -> impl std::future::Future<Output = ()> + Send {
65        async {}
66    }
67
68    /// Subscribe to agent events. Returns `None` if event broadcasting
69    /// is not supported by this host.
70    fn subscribe_events(
71        &self,
72    ) -> Option<tokio::sync::broadcast::Receiver<wcore::protocol::message::AgentEventMsg>> {
73        None
74    }
75
76    /// Handle a tool call not matched by the built-in dispatch table.
77    /// Downstream hosts override this to inject private tools.
78    fn dispatch_custom_tool(
79        &self,
80        name: &str,
81        _args: &str,
82        _agent: &str,
83        _conversation_id: Option<u64>,
84    ) -> impl std::future::Future<Output = String> + Send {
85        async move { format!("tool not available: {name}") }
86    }
87}
88
89/// No-op host for embedded use.
90#[derive(Clone)]
91pub struct NoHost;
92
93impl Host for NoHost {}