Skip to main content

deck_core/
traits.rs

1//! Backend-agnostic trait surface. Each `deck-*` crate is a concrete
2//! implementation of one or more of these traits; the orchestrator depends
3//! only on these abstractions.
4
5use async_trait::async_trait;
6use futures::stream::BoxStream;
7
8use crate::error::Result;
9use crate::message::{Message, ToolCall, ToolResult};
10
11/// A streamable LLM backend (ollama HTTP, llama.cpp in-process, etc).
12#[async_trait]
13pub trait LlmBackend: Send + Sync {
14    /// Human-readable backend identifier (e.g. `"ollama:llama3.1"`).
15    fn id(&self) -> String;
16
17    /// Single-shot completion. Implementations MAY buffer a streamed
18    /// response internally — see [`stream`](Self::stream) for the streamed
19    /// API.
20    async fn complete(&self, model: &str, messages: &[Message]) -> Result<Message>;
21
22    /// Streamed completion. Yields incremental [`Message`] deltas; the last
23    /// delta has the final assistant turn.
24    async fn stream(
25        &self,
26        model: &str,
27        messages: &[Message],
28    ) -> Result<BoxStream<'static, Result<Message>>>;
29}
30
31/// An MCP client connected to a single server (one trait instance per
32/// declared server). Implementations wrap `rmcp` transports.
33#[async_trait]
34pub trait McpClient: Send + Sync {
35    fn server_name(&self) -> &str;
36
37    /// List the tools the server advertises.
38    async fn list_tools(&self) -> Result<Vec<ToolDescriptor>>;
39
40    /// Invoke a tool. The orchestrator is responsible for the human-in-the-
41    /// loop approval; this trait is the raw RPC.
42    async fn call(&self, call: &ToolCall) -> Result<ToolResult>;
43}
44
45#[derive(Debug, Clone)]
46pub struct ToolDescriptor {
47    pub name: String,
48    pub description: String,
49    pub json_schema: serde_json::Value,
50}
51
52/// Encrypted, durable session/context store.
53#[async_trait]
54pub trait Store: Send + Sync {
55    /// Persist (append) a message to a session log.
56    async fn append(&self, session: crate::message::SessionId, msg: &Message) -> Result<()>;
57
58    /// Load all messages for a session, in append order.
59    async fn load(&self, session: crate::message::SessionId) -> Result<Vec<Message>>;
60
61    /// Enumerate sessions stored in this deck.
62    async fn list(&self) -> Result<Vec<crate::message::SessionId>>;
63}
64
65/// Sandbox boundary: wrap an MCP server child process so that any tool
66/// invocation can only access an explicitly granted set of paths and
67/// syscalls.
68pub trait Sandbox: Send + Sync {
69    /// Returns a tag like `"seccomp+landlock"`, `"unsupported(macos)"`.
70    fn availability(&self) -> &'static str;
71
72    /// Whether the current platform can actually enforce a policy.
73    fn enforces(&self) -> bool;
74}