Serving an agent
Implement Agent and hand it to one of the serve_* functions. Only
initialize, new_session and prompt are required — advertise whatever else
you implement in InitializeResponse::agent_capabilities.
use cacp::{Agent, Result, schema};
use std::sync::Arc;
struct Echo;
impl Agent for Echo {
async fn initialize(&self, _: schema::InitializeRequest) -> Result<schema::InitializeResponse> {
Ok(schema::InitializeResponse {
protocol_version: schema::ProtocolVersion::LATEST,
agent_capabilities: Default::default(),
auth_methods: Vec::new(),
agent_info: None,
meta: None,
})
}
async fn new_session(
&self,
_: schema::NewSessionRequest,
) -> Result<schema::NewSessionResponse> {
Ok(schema::NewSessionResponse {
session_id: "session-1".into(),
modes: None,
config_options: None,
meta: None,
})
}
async fn prompt(&self, _: schema::PromptRequest) -> Result<schema::PromptResponse> {
Ok(schema::PromptResponse::new(schema::StopReason::EndTurn))
}
}
#[tokio::main]
async fn main() {
let _client = cacp::serve_on_stdio(Arc::new(Echo));
// The read and write loops run on the runtime; keep the process alive.
std::future::pending::<()>().await
}
That is crates/cacp/examples/agent.rs, included verbatim — cargo test
compiles it, so this page cannot drift from working code.
serve_on_stdio hands back a ClientConn for calling the editor — reporting
progress with session_update, asking permission, reading files through it.
Three ways in, depending on what you already hold:
| function | takes |
|---|---|
serve_on_stdio | this process’s own stdin and stdout |
serve | one duplex stream — a socket, an in-memory pipe |
serve_on | a reader and a writer owned separately |