feat: revision-2025-03-26 without streamable http (#84)
1. Suppot revision 2025-03-26 data types 2. Support meta, progress tokne, and extensions in request/notification, 3. Remove `Message`, use `JsonRpcMessage` directly
This commit is contained in:
parent
cced5e9c2f
commit
68375460df
2 changed files with 1280 additions and 229 deletions
|
|
@ -4,16 +4,16 @@ use thiserror::Error;
|
|||
use super::*;
|
||||
use crate::model::{
|
||||
CallToolRequest, CallToolRequestParam, CallToolResult, CancelledNotification,
|
||||
CancelledNotificationParam, ClientInfo, ClientMessage, ClientNotification, ClientRequest,
|
||||
ClientResult, CompleteRequest, CompleteRequestParam, CompleteResult, GetPromptRequest,
|
||||
GetPromptRequestParam, GetPromptResult, InitializeRequest, InitializedNotification,
|
||||
JsonRpcResponse, ListPromptsRequest, ListPromptsResult, ListResourceTemplatesRequest,
|
||||
ListResourceTemplatesResult, ListResourcesRequest, ListResourcesResult, ListToolsRequest,
|
||||
ListToolsResult, PaginatedRequestParam, PaginatedRequestParamInner, ProgressNotification,
|
||||
ProgressNotificationParam, ReadResourceRequest, ReadResourceRequestParam, ReadResourceResult,
|
||||
RequestId, RootsListChangedNotification, ServerInfo, ServerJsonRpcMessage, ServerNotification,
|
||||
ServerRequest, ServerResult, SetLevelRequest, SetLevelRequestParam, SubscribeRequest,
|
||||
SubscribeRequestParam, UnsubscribeRequest, UnsubscribeRequestParam,
|
||||
CancelledNotificationParam, ClientInfo, ClientJsonRpcMessage, ClientNotification,
|
||||
ClientRequest, ClientResult, CompleteRequest, CompleteRequestParam, CompleteResult,
|
||||
GetPromptRequest, GetPromptRequestParam, GetPromptResult, InitializeRequest,
|
||||
InitializedNotification, JsonRpcResponse, ListPromptsRequest, ListPromptsResult,
|
||||
ListResourceTemplatesRequest, ListResourceTemplatesResult, ListResourcesRequest,
|
||||
ListResourcesResult, ListToolsRequest, ListToolsResult, PaginatedRequestParam,
|
||||
ProgressNotification, ProgressNotificationParam, ReadResourceRequest, ReadResourceRequestParam,
|
||||
ReadResourceResult, RequestId, RootsListChangedNotification, ServerInfo, ServerJsonRpcMessage,
|
||||
ServerNotification, ServerRequest, ServerResult, SetLevelRequest, SetLevelRequestParam,
|
||||
SubscribeRequest, SubscribeRequestParam, UnsubscribeRequest, UnsubscribeRequestParam,
|
||||
};
|
||||
|
||||
/// It represents the error that may occur when serving the client.
|
||||
|
|
@ -141,11 +141,12 @@ where
|
|||
let init_request = InitializeRequest {
|
||||
method: Default::default(),
|
||||
params: service.get_info(),
|
||||
extensions: Default::default(),
|
||||
};
|
||||
sink.send(
|
||||
ClientMessage::Request(ClientRequest::InitializeRequest(init_request), id.clone())
|
||||
.into_json_rpc_message(),
|
||||
)
|
||||
sink.send(ClientJsonRpcMessage::request(
|
||||
ClientRequest::InitializeRequest(init_request),
|
||||
id.clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
let (response, response_id) = expect_response(&mut stream, "initialize response")
|
||||
|
|
@ -166,12 +167,13 @@ where
|
|||
};
|
||||
|
||||
// send notification
|
||||
let notification = ClientMessage::Notification(ClientNotification::InitializedNotification(
|
||||
InitializedNotification {
|
||||
let notification = ClientJsonRpcMessage::notification(
|
||||
ClientNotification::InitializedNotification(InitializedNotification {
|
||||
method: Default::default(),
|
||||
},
|
||||
));
|
||||
sink.send(notification.into_json_rpc_message()).await?;
|
||||
extensions: Default::default(),
|
||||
}),
|
||||
);
|
||||
sink.send(notification).await?;
|
||||
serve_inner(service, (sink, stream), initialize_result, id_provider, ct).await
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +197,22 @@ macro_rules! method {
|
|||
.send_request(ClientRequest::$Req($Req {
|
||||
method: Default::default(),
|
||||
params,
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
match result {
|
||||
ServerResult::$Resp(result) => Ok(result),
|
||||
_ => Err(ServiceError::UnexpectedResponse),
|
||||
}
|
||||
}
|
||||
};
|
||||
(peer_req $method:ident $Req:ident($Param: ident)? => $Resp: ident ) => {
|
||||
pub async fn $method(&self, params: Option<$Param>) -> Result<$Resp, ServiceError> {
|
||||
let result = self
|
||||
.send_request(ClientRequest::$Req($Req {
|
||||
method: Default::default(),
|
||||
params,
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
match result {
|
||||
|
|
@ -209,6 +227,7 @@ macro_rules! method {
|
|||
.send_request(ClientRequest::$Req($Req {
|
||||
method: Default::default(),
|
||||
params,
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
match result {
|
||||
|
|
@ -223,6 +242,7 @@ macro_rules! method {
|
|||
self.send_notification(ClientNotification::$Not($Not {
|
||||
method: Default::default(),
|
||||
params,
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
Ok(())
|
||||
|
|
@ -232,6 +252,7 @@ macro_rules! method {
|
|||
pub async fn $method(&self) -> Result<(), ServiceError> {
|
||||
self.send_notification(ClientNotification::$Not($Not {
|
||||
method: Default::default(),
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
Ok(())
|
||||
|
|
@ -243,14 +264,14 @@ impl Peer<RoleClient> {
|
|||
method!(peer_req complete CompleteRequest(CompleteRequestParam) => CompleteResult);
|
||||
method!(peer_req set_level SetLevelRequest(SetLevelRequestParam));
|
||||
method!(peer_req get_prompt GetPromptRequest(GetPromptRequestParam) => GetPromptResult);
|
||||
method!(peer_req list_prompts ListPromptsRequest(PaginatedRequestParam) => ListPromptsResult);
|
||||
method!(peer_req list_resources ListResourcesRequest(PaginatedRequestParam) => ListResourcesResult);
|
||||
method!(peer_req list_resource_templates ListResourceTemplatesRequest(PaginatedRequestParam) => ListResourceTemplatesResult);
|
||||
method!(peer_req list_prompts ListPromptsRequest(PaginatedRequestParam)? => ListPromptsResult);
|
||||
method!(peer_req list_resources ListResourcesRequest(PaginatedRequestParam)? => ListResourcesResult);
|
||||
method!(peer_req list_resource_templates ListResourceTemplatesRequest(PaginatedRequestParam)? => ListResourceTemplatesResult);
|
||||
method!(peer_req read_resource ReadResourceRequest(ReadResourceRequestParam) => ReadResourceResult);
|
||||
method!(peer_req subscribe SubscribeRequest(SubscribeRequestParam) );
|
||||
method!(peer_req unsubscribe UnsubscribeRequest(UnsubscribeRequestParam));
|
||||
method!(peer_req call_tool CallToolRequest(CallToolRequestParam) => CallToolResult);
|
||||
method!(peer_req list_tools ListToolsRequest(PaginatedRequestParam) => ListToolsResult);
|
||||
method!(peer_req list_tools ListToolsRequest(PaginatedRequestParam)? => ListToolsResult);
|
||||
|
||||
method!(peer_not notify_cancelled CancelledNotification(CancelledNotificationParam));
|
||||
method!(peer_not notify_progress ProgressNotification(ProgressNotificationParam));
|
||||
|
|
@ -267,7 +288,7 @@ impl Peer<RoleClient> {
|
|||
let mut cursor = None;
|
||||
loop {
|
||||
let result = self
|
||||
.list_tools(Some(PaginatedRequestParamInner { cursor }))
|
||||
.list_tools(Some(PaginatedRequestParam { cursor }))
|
||||
.await?;
|
||||
tools.extend(result.tools);
|
||||
cursor = result.next_cursor;
|
||||
|
|
@ -286,7 +307,7 @@ impl Peer<RoleClient> {
|
|||
let mut cursor = None;
|
||||
loop {
|
||||
let result = self
|
||||
.list_prompts(Some(PaginatedRequestParamInner { cursor }))
|
||||
.list_prompts(Some(PaginatedRequestParam { cursor }))
|
||||
.await?;
|
||||
prompts.extend(result.prompts);
|
||||
cursor = result.next_cursor;
|
||||
|
|
@ -305,7 +326,7 @@ impl Peer<RoleClient> {
|
|||
let mut cursor = None;
|
||||
loop {
|
||||
let result = self
|
||||
.list_resources(Some(PaginatedRequestParamInner { cursor }))
|
||||
.list_resources(Some(PaginatedRequestParam { cursor }))
|
||||
.await?;
|
||||
resources.extend(result.resources);
|
||||
cursor = result.next_cursor;
|
||||
|
|
@ -326,7 +347,7 @@ impl Peer<RoleClient> {
|
|||
let mut cursor = None;
|
||||
loop {
|
||||
let result = self
|
||||
.list_resource_templates(Some(PaginatedRequestParamInner { cursor }))
|
||||
.list_resource_templates(Some(PaginatedRequestParam { cursor }))
|
||||
.await?;
|
||||
resource_templates.extend(result.resource_templates);
|
||||
cursor = result.next_cursor;
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use thiserror::Error;
|
|||
use super::*;
|
||||
use crate::model::{
|
||||
CancelledNotification, CancelledNotificationParam, ClientInfo, ClientJsonRpcMessage,
|
||||
ClientMessage, ClientNotification, ClientRequest, ClientResult, CreateMessageRequest,
|
||||
ClientNotification, ClientRequest, ClientResult, CreateMessageRequest,
|
||||
CreateMessageRequestParam, CreateMessageResult, ListRootsRequest, ListRootsResult,
|
||||
LoggingMessageNotification, LoggingMessageNotificationParam, ProgressNotification,
|
||||
ProgressNotificationParam, PromptListChangedNotification, ResourceListChangedNotification,
|
||||
ResourceUpdatedNotification, ResourceUpdatedNotificationParam, ServerInfo, ServerMessage,
|
||||
ServerNotification, ServerRequest, ServerResult, ToolListChangedNotification,
|
||||
ResourceUpdatedNotification, ResourceUpdatedNotificationParam, ServerInfo, ServerNotification,
|
||||
ServerRequest, ServerResult, ToolListChangedNotification,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
|
|
@ -33,10 +33,10 @@ impl ServiceRole for RoleServer {
|
|||
#[derive(Error, Debug)]
|
||||
pub enum ServerError {
|
||||
#[error("expect initialized request, but received: {0:?}")]
|
||||
ExpectedInitRequest(Option<ClientMessage>),
|
||||
ExpectedInitRequest(Option<ClientJsonRpcMessage>),
|
||||
|
||||
#[error("expect initialized notification, but received: {0:?}")]
|
||||
ExpectedInitNotification(Option<ClientMessage>),
|
||||
ExpectedInitNotification(Option<ClientJsonRpcMessage>),
|
||||
|
||||
#[error("connection closed: {0}")]
|
||||
ConnectionClosed(String),
|
||||
|
|
@ -75,15 +75,17 @@ where
|
|||
}
|
||||
|
||||
/// Helper function to get the next message from the stream
|
||||
async fn expect_next_message<S>(stream: &mut S, context: &str) -> Result<ClientMessage, ServerError>
|
||||
async fn expect_next_message<S>(
|
||||
stream: &mut S,
|
||||
context: &str,
|
||||
) -> Result<ClientJsonRpcMessage, ServerError>
|
||||
where
|
||||
S: StreamExt<Item = ClientJsonRpcMessage> + Unpin,
|
||||
{
|
||||
Ok(stream
|
||||
stream
|
||||
.next()
|
||||
.await
|
||||
.ok_or_else(|| ServerError::ConnectionClosed(context.to_string()))?
|
||||
.into_message())
|
||||
.ok_or_else(|| ServerError::ConnectionClosed(context.to_string()))
|
||||
}
|
||||
|
||||
/// Helper function to expect a request from the stream
|
||||
|
|
@ -144,16 +146,28 @@ where
|
|||
|
||||
let ClientRequest::InitializeRequest(peer_info) = request else {
|
||||
return Err(handle_server_error(ServerError::ExpectedInitRequest(Some(
|
||||
ClientMessage::Request(request, id),
|
||||
ClientJsonRpcMessage::request(request, id),
|
||||
))));
|
||||
};
|
||||
|
||||
// Send initialize response
|
||||
let init_response = service.get_info();
|
||||
sink.send(
|
||||
ServerMessage::Response(ServerResult::InitializeResult(init_response), id)
|
||||
.into_json_rpc_message(),
|
||||
)
|
||||
let mut init_response = service.get_info();
|
||||
let protocol_version = match peer_info
|
||||
.params
|
||||
.protocol_version
|
||||
.partial_cmp(&init_response.protocol_version)
|
||||
.ok_or(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"unsupported protocol version",
|
||||
))? {
|
||||
std::cmp::Ordering::Less => peer_info.params.protocol_version.clone(),
|
||||
_ => init_response.protocol_version,
|
||||
};
|
||||
init_response.protocol_version = protocol_version;
|
||||
sink.send(ServerJsonRpcMessage::response(
|
||||
ServerResult::InitializeResult(init_response),
|
||||
id,
|
||||
))
|
||||
.await?;
|
||||
|
||||
// Wait for initialize notification
|
||||
|
|
@ -163,7 +177,7 @@ where
|
|||
|
||||
let ClientNotification::InitializedNotification(_) = notification else {
|
||||
return Err(handle_server_error(ServerError::ExpectedInitNotification(
|
||||
Some(ClientMessage::Notification(notification)),
|
||||
Some(ClientJsonRpcMessage::notification(notification)),
|
||||
)));
|
||||
};
|
||||
|
||||
|
|
@ -177,6 +191,7 @@ macro_rules! method {
|
|||
let result = self
|
||||
.send_request(ServerRequest::$Req($Req {
|
||||
method: Default::default(),
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
match result {
|
||||
|
|
@ -191,6 +206,7 @@ macro_rules! method {
|
|||
.send_request(ServerRequest::$Req($Req {
|
||||
method: Default::default(),
|
||||
params,
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
match result {
|
||||
|
|
@ -224,6 +240,7 @@ macro_rules! method {
|
|||
self.send_notification(ServerNotification::$Not($Not {
|
||||
method: Default::default(),
|
||||
params,
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
Ok(())
|
||||
|
|
@ -233,6 +250,7 @@ macro_rules! method {
|
|||
pub async fn $method(&self) -> Result<(), ServiceError> {
|
||||
self.send_notification(ServerNotification::$Not($Not {
|
||||
method: Default::default(),
|
||||
extensions: Default::default(),
|
||||
}))
|
||||
.await?;
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Reference in a new issue