Skip to content

Commit 2298dd0

Browse files
committed
wip
1 parent 94dfb6c commit 2298dd0

5 files changed

Lines changed: 26 additions & 16 deletions

File tree

src/sacp/src/jsonrpc/responder.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use crate::{JrConnectionCx, role::JrRole};
1212
///
1313
/// Responders are composed using [`ChainResponder`] and run in parallel
1414
/// when the connection is active.
15-
pub trait JrResponder<Role: JrRole>: Send {
15+
#[expect(async_fn_in_trait)]
16+
pub trait JrResponder<Role: JrRole> {
1617
/// Run this responder to completion.
17-
fn run(self, cx: JrConnectionCx<Role>)
18-
-> impl Future<Output = Result<(), crate::Error>> + Send;
18+
async fn run(self, cx: JrConnectionCx<Role>) -> Result<(), crate::Error>;
1919
}
2020

2121
/// A no-op responder that completes immediately.

src/sacp/src/mcp_server/builder.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@ where
140140
where
141141
P: JsonSchema + DeserializeOwned + 'static + Send,
142142
R: JsonSchema + Serialize + 'static + Send,
143-
F: FnMut(P, McpContext<Role>) -> Fut + Send + Sync,
144-
Fut: std::future::Future<Output = Result<R, crate::Error>> + Send,
143+
F: AsyncFnMut(P, McpContext<Role>) -> Result<R, crate::Error>,
145144
{
146145
struct ToolFnTool<P, R, Role: JrRole> {
147146
name: String,

src/sacp/src/mcp_server/responder.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! MCP-specific responder types.
22
3-
use std::future::Future;
4-
53
use futures::{StreamExt, channel::mpsc};
64

75
use crate::{JrConnectionCx, JrRole, jsonrpc::responder::JrResponder, mcp_server::McpContext};
@@ -20,13 +18,12 @@ pub struct ToolFnResponder<F, P, R, Role: JrRole> {
2018
pub(crate) call_rx: mpsc::Receiver<ToolCall<P, R, Role>>,
2119
}
2220

23-
impl<F, P, R, Role, Fut> JrResponder<Role> for ToolFnResponder<F, P, R, Role>
21+
impl<F, P, R, Role> JrResponder<Role> for ToolFnResponder<F, P, R, Role>
2422
where
2523
Role: JrRole,
2624
P: Send,
2725
R: Send,
28-
F: FnMut(P, McpContext<Role>) -> Fut + Send,
29-
Fut: Future<Output = Result<R, crate::Error>> + Send,
26+
F: AsyncFnMut(P, McpContext<Role>) -> Result<R, crate::Error>,
3027
{
3128
async fn run(mut self, _cx: JrConnectionCx<Role>) -> Result<(), crate::Error> {
3229
while let Some(ToolCall {

src/sacp/src/session.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,21 @@ where
145145
.await
146146
}
147147

148-
/// Send the request to create the session.
149-
pub async fn send_request(self) -> Result<ActiveSession<Role>, crate::Error>
148+
/// Send the request to create the session and return a handle.
149+
/// This is an alternative to [`Self::run_session`] that avoids rightward
150+
/// drift but at the cost of requiring MCP servers that are `Send` and
151+
/// don't access data from the surrounding scope.
152+
///
153+
/// # Parameters
154+
///
155+
/// * `run_responder`: this is typically just `Responder::run`;
156+
/// the need for this parameter is a workaround for Rust limitations.
157+
pub async fn send_request<F>(
158+
self,
159+
run_responder: impl FnOnce(Responder, JrConnectionCx<Role>) -> F,
160+
) -> Result<ActiveSession<Role>, crate::Error>
150161
where
151-
Responder: 'static,
162+
F: Future<Output = Result<(), crate::Error>> + Send + 'static,
152163
{
153164
let response = self
154165
.connection
@@ -157,7 +168,7 @@ where
157168
.await?;
158169

159170
let cx = self.connection.clone();
160-
self.connection.spawn(self.responder.run(cx))?;
171+
self.connection.spawn(run_responder(self.responder, cx))?;
161172

162173
self.connection
163174
.attach_session(response, self.dynamic_handler_registrations)

src/yopo/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
//!
33
//! Provides a convenient API for running one-shot prompts against SACP components.
44
5-
use sacp::ClientToAgent;
65
use sacp::schema::{
76
AudioContent, ContentBlock, EmbeddedResourceResource, ImageContent, InitializeRequest,
87
RequestPermissionOutcome, RequestPermissionRequest, RequestPermissionResponse,
98
SessionNotification, TextContent, VERSION as PROTOCOL_VERSION,
109
};
1110
use sacp::util::MatchMessage;
11+
use sacp::{ClientToAgent, JrResponder};
1212
use sacp::{Component, Handled, MessageCx, UntypedMessage};
1313
use std::path::PathBuf;
1414

@@ -112,7 +112,10 @@ pub async fn prompt_with_callback(
112112
.block_task()
113113
.await?;
114114

115-
let mut session = cx.build_session(PathBuf::from(".")).send_request().await?;
115+
let mut session = cx
116+
.build_session(PathBuf::from("."))
117+
.send_request(JrResponder::run)
118+
.await?;
116119

117120
session.send_prompt(prompt_text)?;
118121

0 commit comments

Comments
 (0)