Skip to content

Commit 720cdab

Browse files
committed
chore: run prettier
1 parent 5da43bb commit 720cdab

File tree

1 file changed

+37
-37
lines changed

1 file changed

+37
-37
lines changed

docs/rfds/rust-sdk-v2.mdx

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Replace the current ACP Rust SDK with a new implementation based on SACP (Sympos
1616
1717
The current `agent-client-protocol` crate has a straightforward design with trait-based callbacks for common ACP methods and well-typed requests and responses. It's convenient for simple purposes but quickly becomes awkward when attempting more complex designs.
1818

19-
Two examples that we found pushed the limits of the design are the *conductor* (from the [proxy chains](./proxy-chains) RFD) and the [patchwork-rs](https://patchwork-lang.github.io/patchwork-rs/) project:
19+
Two examples that we found pushed the limits of the design are the _conductor_ (from the [proxy chains](./proxy-chains) RFD) and the [patchwork-rs](https://patchwork-lang.github.io/patchwork-rs/) project:
2020

2121
The Conductor is an orchestrator that routes messages between proxies, agents, and MCP servers. It must adapt messages as they flow through the system and maintain the correct ordering.
2222

@@ -80,7 +80,7 @@ In the current SDK, every incoming request or notification results is handled in
8080

8181
### Limitation: Confusing naming and 1:1 assumption
8282

83-
`AgentSideConnection` is ambiguous - does this represent the agent, or the connection *to* an agent? What's more, the SDK currently assumes that each connection has a single peer, but [proxies](./proxy-chains) may wish to send/receive messages from multiple peers (client or agent). This was a constant source of confusion in early versions of the conductor and frequently required the author to get out a pencil and paper and work things out very carefully.
83+
`AgentSideConnection` is ambiguous - does this represent the agent, or the connection _to_ an agent? What's more, the SDK currently assumes that each connection has a single peer, but [proxies](./proxy-chains) may wish to send/receive messages from multiple peers (client or agent). This was a constant source of confusion in early versions of the conductor and frequently required the author to get out a pencil and paper and work things out very carefully.
8484

8585
**Goal:** Use directional naming like `ClientToAgent` that makes relationships explicit: "I am the client, the remote peer is an agent." Enable multiple peers.
8686

@@ -94,7 +94,7 @@ When building tests and other applications, it's convenient to be able to create
9494

9595
This isn't a limitation of the current SDK per se, but a common pitfall in async Rust designs that we want to address.
9696

97-
We want the SDK to be independent from specific executors (not tied to tokio) while still supporting richer patterns like spawning background tasks. One specific common issue with Rust async APIs is *starvation*, which can occur with stream-like APIs where it is important to keep awaiting the stream so that items make progress. For example, in a setup like this one, the "connection" is not being "awaited" while each message is handled:
97+
We want the SDK to be independent from specific executors (not tied to tokio) while still supporting richer patterns like spawning background tasks. One specific common issue with Rust async APIs is _starvation_, which can occur with stream-like APIs where it is important to keep awaiting the stream so that items make progress. For example, in a setup like this one, the "connection" is not being "awaited" while each message is handled:
9898

9999
```rust
100100
// PROBLEMATIC: message handling starves while processing
@@ -124,23 +124,23 @@ We propose to replace the current Rust SDK with [`sacp`](https://github.com/symp
124124

125125
The following table summarizes the key API concepts and which goals they address:
126126

127-
| API Concept | Goals Addressed |
128-
|-------------|-----------------|
129-
| [Link types](#link-types-and-directional-naming) (`ClientToAgent`, `AgentToClient`) | Confusing naming, 1:1 assumption |
130-
| [`Component` trait + `connect_to`](#the-component-trait-and-connect_to) | Awkward to connect components |
131-
| [Connection context (`cx`)](#sending-messages) | Handlers can't send messages |
132-
| [`on_receive_*` handlers](#handling-messages) with closure types | Fixed set of handlers |
133-
| [`serve` / `run_until`](#running-connections-serve-and-run_until) | Executor independence, starvation freedom |
134-
| [Session builders + dynamic handlers](#session-builders-and-mcp-servers) | Handlers must be same across sessions |
135-
| [Ordering guarantees + `spawn`](#controlling-ordering) | No ordering guarantees |
127+
| API Concept | Goals Addressed |
128+
| ----------------------------------------------------------------------------------- | ----------------------------------------- |
129+
| [Link types](#link-types-and-directional-naming) (`ClientToAgent`, `AgentToClient`) | Confusing naming, 1:1 assumption |
130+
| [`Component` trait + `connect_to`](#the-component-trait-and-connect_to) | Awkward to connect components |
131+
| [Connection context (`cx`)](#sending-messages) | Handlers can't send messages |
132+
| [`on_receive_*` handlers](#handling-messages) with closure types | Fixed set of handlers |
133+
| [`serve` / `run_until`](#running-connections-serve-and-run_until) | Executor independence, starvation freedom |
134+
| [Session builders + dynamic handlers](#session-builders-and-mcp-servers) | Handlers must be same across sessions |
135+
| [Ordering guarantees + `spawn`](#controlling-ordering) | No ordering guarantees |
136136

137137
We have validated the design by implementing a number of use cases:
138138

139-
* [sacp-conductor](https://github.com/symposium-dev/symposium-acp/tree/main/src/sacp-conductor) - proxy chain orchestrator
140-
* [Patchwork](https://patchwork-lang.github.io/patchwork-rs/) - programmatic agent orchestration
141-
* [elizacp](https://github.com/symposium-dev/symposium-acp/tree/main/src/elizacp) - agent implementing the classic ELIZA program
142-
* [sacp-tee](https://crates.io/crates/sacp-tee) - proxy that logs messages before forwarding
143-
* [yopo](https://crates.io/crates/yopo) ("You Only Prompt Once") - CLI tool for single prompts
139+
- [sacp-conductor](https://github.com/symposium-dev/symposium-acp/tree/main/src/sacp-conductor) - proxy chain orchestrator
140+
- [Patchwork](https://patchwork-lang.github.io/patchwork-rs/) - programmatic agent orchestration
141+
- [elizacp](https://github.com/symposium-dev/symposium-acp/tree/main/src/elizacp) - agent implementing the classic ELIZA program
142+
- [sacp-tee](https://crates.io/crates/sacp-tee) - proxy that logs messages before forwarding
143+
- [yopo](https://crates.io/crates/yopo) ("You Only Prompt Once") - CLI tool for single prompts
144144

145145
The [Deep dive](#deep-dive) section below walks through each concept in detail. Code examples are also available in the [sacp-cookbook crate](https://docs.rs/sacp-cookbook/latest/sacp_cookbook/).
146146

@@ -152,10 +152,10 @@ This section walks through the SDK concepts in detail, organized by what you're
152152

153153
#### Link types and directional naming
154154

155-
The SDK is organized around *link types* that describe who you are and who you're talking to. The two most common examples are:
155+
The SDK is organized around _link types_ that describe who you are and who you're talking to. The two most common examples are:
156156

157-
* `ClientToAgent` - "I am a client, connecting to an agent"
158-
* `AgentToClient` - "I am an agent, serving a client"
157+
- `ClientToAgent` - "I am a client, connecting to an agent"
158+
- `AgentToClient` - "I am an agent, serving a client"
159159

160160
To build a connection, start with the link type and invoke the `builder` method. Builders use the typical "fluent" style:
161161

@@ -234,7 +234,7 @@ AgentToClient::builder()
234234
.await
235235
```
236236

237-
**`run_until()`** takes an async closure and runs your code concurrently with message handling. The closure receives a *connection context* (conventionally called `cx`) - this is how you interact with the connection, sending messages, spawning tasks, and adding dynamic handlers. When the closure returns, the connection closes:
237+
**`run_until()`** takes an async closure and runs your code concurrently with message handling. The closure receives a _connection context_ (conventionally called `cx`) - this is how you interact with the connection, sending messages, spawning tasks, and adding dynamic handlers. When the closure returns, the connection closes:
238238

239239
```rust
240240
ClientToAgent::builder()
@@ -250,7 +250,7 @@ ClientToAgent::builder()
250250
.await
251251
```
252252

253-
The `run_until` pattern directly addresses starvation. Instead of exposing an async stream that users might accidentally block, `run_until` runs your code *concurrently* with message handling.
253+
The `run_until` pattern directly addresses starvation. Instead of exposing an async stream that users might accidentally block, `run_until` runs your code _concurrently_ with message handling.
254254

255255
The `cx` type (`JrConnectionCx`) follows the "handle" pattern: cloned values refer to the same connection. It's `'static` so it can be sent across threads or stored in structs. Handlers registered with `on_receive_*` also receive a `cx` parameter.
256256

@@ -342,7 +342,7 @@ Use `cx.spawn` to run work concurrently with message handling:
342342
/* ... */
343343
Ok(())
344344
})?;
345-
345+
346346
// Handler returns immediately, spawned work continues
347347
request_cx.respond(/* ... */)
348348
}, sacp::on_receive_request!())
@@ -422,7 +422,7 @@ When you need to start a session from inside an `on_receive_*` handler but can't
422422
let response = session.read_to_string().await?;
423423
Ok(())
424424
})?;
425-
425+
426426
// Handler returns immediately, session runs in background
427427
Ok(())
428428
}, sacp::on_receive_request!())
@@ -456,7 +456,7 @@ For proxies that want to inject MCP servers but otherwise forward all messages,
456456
.block_task()
457457
.start_session_proxy(request_cx)
458458
.await?;
459-
459+
460460
// Session messages are automatically proxied between client and agent
461461
Ok(())
462462
}, sacp::on_receive_request!())
@@ -492,7 +492,7 @@ Request handlers receive an additional `request_cx` parameter for sending the re
492492
async |req: PromptRequest, request_cx, cx| {
493493
// Process the request...
494494
cx.send_notification(StatusNotification::new("processing"))?;
495-
495+
496496
// Send the response
497497
request_cx.respond(PromptResponse::new(StopReason::EndTurn))
498498
},
@@ -579,25 +579,25 @@ Use `on_receive_message` with `MessageCx` to intercept any incoming message (req
579579

580580
#### Handler chains
581581

582-
A *message handler* takes ownership of a message and either handles it or returns a (possibly modified) copy to be tried by the next handler. Handlers are chained together - each gets a chance to claim the message before it passes to the next.
582+
A _message handler_ takes ownership of a message and either handles it or returns a (possibly modified) copy to be tried by the next handler. Handlers are chained together - each gets a chance to claim the message before it passes to the next.
583583

584584
```mermaid
585585
flowchart TD
586586
MSG[Incoming Message] --> STATIC
587-
587+
588588
subgraph STATIC[Static Handlers]
589589
S1[Handler 1] --> S2[Handler 2] --> S3[Handler n...]
590590
end
591-
591+
592592
STATIC -->|not claimed| DYNAMIC
593-
593+
594594
subgraph DYNAMIC[Dynamic Handlers]
595595
D1[Session handlers, etc.]
596596
end
597-
597+
598598
DYNAMIC -->|not claimed| DEFAULT[Link Default Handler]
599599
DEFAULT -->|not claimed| UNHANDLED{Unhandled}
600-
600+
601601
UNHANDLED -->|retry: false| ERROR[Send error response]
602602
UNHANDLED -->|retry: true| QUEUE[Queue for retry]
603603
QUEUE -->|new handler added| DYNAMIC
@@ -616,7 +616,7 @@ The `JrMessageHandler` trait defines how handlers work:
616616
```rust
617617
pub trait JrMessageHandler: Send {
618618
type Link: JrLink;
619-
619+
620620
async fn handle_message(
621621
&mut self,
622622
message: MessageCx,
@@ -682,7 +682,7 @@ When implementing `JrMessageHandler` directly, `MatchMessage` provides ergonomic
682682
```rust
683683
impl JrMessageHandler for MyHandler {
684684
type Link = AgentToClient;
685-
685+
686686
async fn handle_message(
687687
&mut self,
688688
message: MessageCx,
@@ -788,15 +788,15 @@ pub struct MyCustomLink;
788788

789789
impl JrLink for MyCustomLink {
790790
type ConnectsTo = OtherSideLink;
791-
791+
792792
fn direction() -> LinkDirection {
793793
LinkDirection::Outbound // We initiate the connection
794794
}
795-
795+
796796
fn default_request_handling() -> DefaultHandling {
797797
DefaultHandling::Error // Unknown requests return an error
798798
}
799-
799+
800800
fn default_notification_handling() -> DefaultHandling {
801801
DefaultHandling::Ignore // Unknown notifications are silently dropped
802802
}

0 commit comments

Comments
 (0)