Skip to main content

Module callbacks

Module callbacks 

Source
Expand description

Handling incoming messages with on_receive_* callbacks.

So far we’ve seen how to send messages. But ACP is bidirectional - the remote peer can also send messages to you. Use callbacks to handle them.

§Handling Requests

Use on_receive_request to handle incoming requests that expect a response:

Client.builder()
    .on_receive_request(async |req: ValidateRequest, responder, cx| {
        // Process the request
        let is_valid = req.data.len() > 0;

        // Send the response
        responder.respond(ValidateResponse { is_valid, error: None })
    }, agent_client_protocol::on_receive_request!())
    .connect_with(transport, async |cx| { Ok(()) })
    .await?;

Your callback receives three arguments:

  • The request payload (e.g., PermissionRequest)
  • A Responder for sending the response
  • A ConnectionTo for sending other messages

§Handling Notifications

Use on_receive_notification for fire-and-forget messages that don’t need a response:

Client.builder()
    .on_receive_notification(async |notif: StatusUpdate, cx| {
        println!("Status: {}", notif.message);
        Ok(())
    }, agent_client_protocol::on_receive_notification!())

§The Request Context

The Responder lets you send a response to the request:

// Send a successful response
responder.respond(MyResponse { status: "ok".into() })?;

Or send an error:

responder.respond_with_error(agent_client_protocol::Error::invalid_params())?;

You must send exactly one response per request. If your callback returns without responding, an error response is sent automatically.

§Multiple Handlers

You can register multiple handlers. They’re tried in order until one handles the message:

Client.builder()
    .on_receive_request(async |req: ValidateRequest, responder, cx| {
        // Handle validation requests
        responder.respond(ValidateResponse { is_valid: true, error: None })
    }, agent_client_protocol::on_receive_request!())
    .on_receive_request(async |req: ExecuteRequest, responder, cx| {
        // Handle execution requests
        responder.respond(ExecuteResponse { result: "done".into() })
    }, agent_client_protocol::on_receive_request!())

§Ordering Guarantees

Callbacks run inside the dispatch loop and block further message processing until they complete. This gives you ordering guarantees but also means you need to be careful about deadlocks.

See Ordering for the full details.

§Next Steps

  • Explicit Peers - Use _from variants to specify the source peer
  • Ordering - Understand dispatch loop semantics