SessionBuilder

Struct SessionBuilder 

Source
pub struct SessionBuilder<Link, Responder: JrResponder<Link> = NullResponder, BlockState: SessionBlockState = NonBlocking>
where Link: HasPeer<AgentPeer>,
{ /* private fields */ }
Expand description

Session builder for a new session request. Allows you to add MCP servers or set other details for this session.

The BlockState type parameter tracks whether blocking methods are available:

Implementations§

Source§

impl<Link, Responder, BlockState> SessionBuilder<Link, Responder, BlockState>
where Link: HasPeer<AgentPeer>, Responder: JrResponder<Link>, BlockState: SessionBlockState,

Source

pub fn with_mcp_server<R>( self, mcp_server: McpServer<Link, R>, ) -> Result<SessionBuilder<Link, ChainResponder<Responder, R>, BlockState>, Error>
where R: JrResponder<Link>,

Add the MCP servers from the given registry to this session.

Source

pub fn on_session_start<F, Fut>(self, op: F) -> Result<(), Error>
where Responder: 'static, F: FnOnce(ActiveSession<'static, Link>) -> Fut + Send + 'static, Fut: Future<Output = Result<(), Error>> + Send,

Spawn a task that runs the provided closure once the session starts.

Unlike start_session, this method returns immediately without blocking the current task. The session handshake and closure execution happen in a spawned background task.

The closure receives an ActiveSession<'static, _> and should return Result<(), Error>. If the closure returns an error, it will propagate to the connection’s error handling.

§Example
cx.build_session_cwd()?
    .with_mcp_server(mcp)?
    .on_session_start(async |mut session| {
        // Do something with the session
        session.send_prompt("Hello")?;
        let response = session.read_to_string().await?;
        Ok(())
    })?;
// Returns immediately, session runs in background
§Ordering

This callback blocks the dispatch loop until the session starts and your callback completes. See the ordering module for details.

Source

pub fn on_proxy_session_start<F, Fut>( self, request_cx: JrRequestCx<NewSessionResponse>, op: F, ) -> Result<(), Error>
where F: FnOnce(SessionId) -> Fut + Send + 'static, Fut: Future<Output = Result<(), Error>> + Send, Link: HasPeer<ClientPeer>, Responder: 'static,

Spawn a proxy session and run a closure with the session ID.

A proxy session starts the session with the agent and then automatically proxies all session updates (prompts, tool calls, etc.) from the agent back to the client. You don’t need to handle any messages yourself - the proxy takes care of forwarding everything. This is useful when you want to inject and/or filter prompts coming from the client but otherwise not be involved in the session.

Unlike start_session_proxy, this method returns immediately without blocking the current task. The session handshake, client response, and proxy setup all happen in a spawned background task.

The closure receives the SessionId once the session is established, allowing you to perform any custom work with that ID (e.g., tracking, logging).

§Example
ProxyToConductor::builder()
    .on_receive_request_from(ClientPeer, async |request: NewSessionRequest, request_cx, cx| {
        let mcp = McpServer::<ProxyToConductor, _>::builder("tools").build();
        cx.build_session_from(request)
            .with_mcp_server(mcp)?
            .on_proxy_session_start(request_cx, async |session_id| {
                // Session started
                Ok(())
            })
    }, sacp::on_receive_request!())
    .serve(transport)
    .await?;
§Ordering

This callback blocks the dispatch loop until the session starts and your callback completes. See the ordering module for details.

Source§

impl<Link, Responder> SessionBuilder<Link, Responder, NonBlocking>
where Link: HasPeer<AgentPeer>, Responder: JrResponder<Link>,

Source

pub fn block_task(self) -> SessionBuilder<Link, Responder, Blocking>

Mark this session builder as being able to block the current task.

After calling this, you can use run_until or start_session which block the current task.

This should not be used from inside a message handler like JrConnectionBuilder::on_receive_request or JrMessageHandler implementations.

Source§

impl<Link, Responder> SessionBuilder<Link, Responder, Blocking>
where Link: HasPeer<AgentPeer>, Responder: JrResponder<Link>,

Source

pub async fn run_until<R>( self, op: impl for<'responder> AsyncFnOnce(ActiveSession<'responder, Link>) -> Result<R, Error>, ) -> Result<R, Error>

Run this session synchronously. The current task will be blocked and op will be executed with the active session information. This is useful when you have MCP servers that are borrowed from your local stack frame.

The ActiveSession passed to op has a non-'static lifetime, which prevents calling ActiveSession::proxy_remaining_messages (since the responders would terminate when op returns).

Requires calling block_task first.

Source

pub async fn start_session(self) -> Result<ActiveSession<'static, Link>, Error>
where Responder: 'static,

Send the request to create the session and return a handle. This is an alternative to Self::run_until that avoids rightward drift but at the cost of requiring MCP servers that are Send and don’t access data from the surrounding scope.

Returns an ActiveSession<'static, _> because responders are spawned into background tasks that live for the connection lifetime.

Requires calling block_task first.

Source

pub async fn start_session_proxy( self, request_cx: JrRequestCx<NewSessionResponse>, ) -> Result<SessionId, Error>
where Link: HasPeer<ClientPeer>, Responder: 'static,

Start a proxy session that forwards all messages between client and agent.

A proxy session starts the session with the agent and then automatically proxies all session updates (prompts, tool calls, etc.) from the agent back to the client. You don’t need to handle any messages yourself - the proxy takes care of forwarding everything. This is useful when you want to inject and/or filter prompts coming from the client but otherwise not be involved in the session.

This is a convenience method that combines start_session, responding to the client, and ActiveSession::proxy_remaining_messages.

For more control (e.g., to send some messages before proxying), use start_session instead and call proxy_remaining_messages manually.

Requires calling block_task first.

Auto Trait Implementations§

§

impl<Link, Responder, BlockState> Freeze for SessionBuilder<Link, Responder, BlockState>
where Responder: Freeze, Link: Freeze,

§

impl<Link, Responder = NullResponder, BlockState = NonBlocking> !RefUnwindSafe for SessionBuilder<Link, Responder, BlockState>

§

impl<Link, Responder, BlockState> Send for SessionBuilder<Link, Responder, BlockState>

§

impl<Link, Responder, BlockState> Sync for SessionBuilder<Link, Responder, BlockState>
where Responder: Sync,

§

impl<Link, Responder, BlockState> Unpin for SessionBuilder<Link, Responder, BlockState>
where Responder: Unpin, Link: Unpin, BlockState: Unpin,

§

impl<Link, Responder = NullResponder, BlockState = NonBlocking> !UnwindSafe for SessionBuilder<Link, Responder, BlockState>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoMaybeUndefined<T> for T

Source§

impl<T> IntoOption<T> for T

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more