Skip to content

Comments

refactor(sacp)!: Role-based API replacing Link/Peer system#115

Merged
nikomatsakis merged 19 commits intomainfrom
the-big-rename
Jan 19, 2026
Merged

refactor(sacp)!: Role-based API replacing Link/Peer system#115
nikomatsakis merged 19 commits intomainfrom
the-big-rename

Conversation

@nikomatsakis
Copy link
Contributor

Summary

This PR introduces a simpler Role-based API that replaces the previous Link/Peer system. The main goals are:

  • Eliminate the Jr prefix from type names (JrConnectionCxConnectionTo, JrResponseSentRequest)
  • Replace Link types with Role types - Instead of encoding both sides (ClientToAgent, AgentToClient), Role types encode one side (Client, Agent)
  • Simplify the builder API with clearer method names (.serve().connect_to())
  • Unify peer and role types - Agent, Client, Proxy, Conductor serve as role types, peer selectors, AND builder starters

The New API

Building a Client

use sacp::{Client, Agent, ConnectTo};

Client.connect_from()
    .name("my-client")
    .connect_with(transport, async |connection| {
        connection.send_request(InitializeRequest::new(ProtocolVersion::LATEST))
            .block_task().await?;
        Ok(())
    })
    .await

Building an Agent

use sacp::{Agent, Client, ConnectTo};

Agent.connect_from()
    .name("my-agent")
    .on_receive_request(async |req: InitializeRequest, responder, _connection| {
        responder.respond(InitializeResponse::new(req.protocol_version))
    }, sacp::on_receive_request!())
    .connect_to(transport)
    .await

Implementing ConnectTo (was Component)

use sacp::{ConnectTo, Agent, Client};

impl ConnectTo<Client> for MyAgent {
    async fn connect_to(self, client: impl ConnectTo<Agent>) -> Result<(), sacp::Error> {
        Agent.connect_from()
            .name("my-agent")
            // handlers...
            .connect_to(client)
            .await
    }
}

Key Renames

v10 (old) v11 (new)
Component<L> ConnectTo<R>
ClientToAgent, AgentToClient Client, Agent
ProxyToConductor Proxy, Conductor
JrConnectionCx<L> ConnectionTo<R>
JrRequestCx<T> Responder<T>
JrResponse<T> SentRequest<T>
MessageCx Dispatch
.serve(transport) .connect_to(transport)
.run_until(transport, fn) .connect_with(transport, fn)
request_cx responder
cx connection

Migration Guide

A comprehensive migration guide is available at md/v10_to_v11_upgrade.md with:

  • Complete type and method rename tables
  • 10 common upgrade patterns with before/after examples
  • Conceptual explanation of Role vs Link
  • Migration tips

Breaking Changes

This is a breaking change affecting all downstream code. The changes are mostly mechanical renames that can be done with search-and-replace, guided by the migration document.


🤖 Generated with Claude Code

nikomatsakis and others added 19 commits January 16, 2026 19:46
- JrMessage → JsonRpcMessage
- JrRequest → JsonRpcRequest
- JrNotification → JsonRpcNotification
- JrResponsePayload → JsonRpcResponse
- JrRequestCx → JsonRpcRequestCx
Reverts the unintended renames:
- JsonRpcMessageHandler → JrMessageHandler
- JsonRpcRequestCx → JrRequestCx

These were accidentally renamed in f23ac47 but were not part of
the requested changes.
Phase 1 of the role-based API refactoring. Adds:
- Role trait with Counterpart associated type and default_message_handler
- role::HasPeer<Peer> trait with remote_style
- RoleId for identifying role instances
- Four role types: Client, Agent, Proxy, Conductor

Key design decisions:
- Proxy::Counterpart = Conductor (who it connects to)
- Proxy has HasPeer<Client> and HasPeer<Agent> but NOT HasPeer<Conductor>
  (conductor is the transport, not a message destination)
- ConnectionTo<R> placeholder for Phase 2

This runs parallel to the existing Link/JrPeer system during migration.
- JrResponder trait -> Run
- NullResponder -> NullRun
- ChainResponder -> ChainRun
- SpawnedResponder -> SpawnedRun
- Renamed jsonrpc/responder.rs -> jsonrpc/run.rs

This frees up 'Responder' for use as the new name for JrRequestCx
in Phase 3.
- JrConnectionCx → ConnectionTo
- JrRequestCx → Responder
- JrResponseCx → ResponseRouter

Removed placeholder ConnectionTo from role.rs and fixed type parameter
collisions in session.rs (Responder type param → R, run_until R → T).
- spawn_connection now takes (builder, transport) instead of (connection, serve_fn)
- JrConnection is now internal (not publicly exported)
- Updated all call sites and documentation
- Convenience methods serve() and run_until() remain on JrConnectionBuilder
Step 0 of Phase 6 - Link→Role migration.

The new name better reflects the semantics: a handler that handles
messages from a particular role. Deprecated alias JrMessageHandler
is preserved for backward compatibility.
Replace the dual JrLink/JrPeer type system with a single unified Role-based API.
This simplifies the mental model: roles are now both the identity (Client, Agent,
Proxy, Conductor) and the peer type for message routing.

Key changes:
- Component<L> → Serve<R>: "I serve someone playing role R"
- DynComponent<L> → DynServe<R>
- ClientToAgent/AgentToClient → Client/Agent (roles are their own link types)
- AgentPeer/ClientPeer → Agent/Client (roles are their own peer types)
- Conductor struct → ConductorImpl (Conductor is now a role)
- Run trait → RunWithConnectionTo
- New module structure: role/acp.rs and role/mcp.rs

Removed:
- src/sacp/src/peer.rs (JrPeer system)
- src/sacp/src/mcp.rs (moved to role/mcp.rs)
- src/sacp-tee/ crate (no longer maintained)

BREAKING CHANGE: All Component/DynComponent usage must change to Serve/DynServe.
All JrLink types (ClientToAgent, etc.) replaced with Role types (Client, Agent).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Serve<R> → ConnectTo<R>
- DynServe<R> → DynConnectTo<R>
- .serve(transport) → .connect_to(transport)
- ::builder() → .connect_from()
- .run_until(transport, ...) → .connect_with(transport, ...)
- .into_server() → .into_channel_and_future()

The new naming better expresses the intent: ConnectTo<R> means
"I can connect to something playing role R", and Agent.connect_from()
reads as "build a connection from a client to this agent".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update all doctests to use the new API patterns from the big rename:
- Replace link types (ClientToAgent, AgentToClient, etc.) with role types (Client, Agent, Proxy, Conductor)
- Change .run_until(transport, ...) to .connect_with(transport, ...)
- Change .serve(transport) to .connect_to(transport)
- Update transport bounds to use ConnectTo<Role> pattern
- Update MCP server type parameters to use counterpart roles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
A Dispatch is the combination of an incoming message along with the
types needed to process it (Responder for requests, ResponseRouter
for responses). This rename clarifies the purpose of the type.

- MessageCx → Dispatch
- MatchMessage → MatchDispatch
- on_receive_message → on_receive_dispatch
- message_cx variables → dispatch
- Remove JrMessageHandler backward-compat alias

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace abbreviated context variable names with clearer, more
descriptive alternatives throughout the codebase.

| Old Name | New Name |
|----------|----------|
| `request_cx` | `responder` |
| `response_cx` | `router` |
| `connection_cx` | `connection` |
| `agent_cx` | `connection_to_agent` |
| `client_cx` | `connection_to_client` |
| `editor_cx` | `connection_to_editor` |
| `conductor_cx` | `connection_to_conductor` |
| `mcp_cx` | `mcp_connection` |
| `backend_cx` | `backend_connection` |
| `json_rpc_cx` | `connection` |
| `forward_to_request_cx` | `forward_response_to` |
| SessionBuilder field `responder` | `run` |

BREAKING CHANGE: All *_cx variable names have been replaced with
more descriptive alternatives. Code using these patterns will need
to update variable names accordingly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Renames for consistency with Dispatch terminology:
- HandleMessageFrom → HandleDispatchFrom
- handle_message (trait method) → handle_dispatch_from
- handle_message_from → handle_dispatch_from
- default_handle_message_from → default_handle_dispatch_from
- handle_incoming_message → handle_incoming_dispatch

Also adds v10 to v11 upgrade guide (md/v10_to_v11_upgrade.md) documenting
all breaking changes and migration patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update all doctests and examples to use the new v11 API:
- Replace Link types (ClientToAgent, AgentToClient, ProxyToConductor) with
  Role types (Client, Agent, Proxy, Conductor)
- Replace Component trait with ConnectTo trait
- Replace .serve() with .connect_to() and .run_until() with .connect_with()
- Rename callback parameters (cx → connection, request_cx → responder)
- Update HandleDispatchFrom to use generic parameter instead of associated type
- Replace Run with RunWithConnectionTo

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update documentation links across the workspace to use new v11 type
and method names:

- JrConnection → ConnectFrom
- JrResponse → SentRequest
- Component → ConnectTo
- serve → connect_to
- run_until → connect_with
- HandleMessageAs → HandleDispatchFrom
- RunIn → RunWithConnectionTo
- McpContext → McpConnectionTo

Also fix link syntax issues in cookbook using inline (sacp::Type)
syntax instead of reference-style links.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The mdbook now focuses on design documentation for maintainers and
agents working on the codebase. Users building with sacp are directed
to the rustdoc and cookbook.

Changes:
- Remove API usage docs (building-agent.md, building-proxy.md) - covered by cookbook
- Remove architecture.md, pacp-components.md, chapter_1.md - redundant
- Add sacp-design.md explaining role system, dispatch loop, connections
- Rewrite introduction.md with crate structure and rustdoc links
- Update conductor.md and protocol.md to remove code examples
- Reorganize SUMMARY.md into Core Library / Conductor / Reference sections

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@nikomatsakis nikomatsakis merged commit 16637e6 into main Jan 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant