Пакетные запросы
Neva поддерживает пакетные запросы JSON-RPC 2.0 — способ отправить несколько запросов к серверу за один сетевой обмен и получить все ответы сразу. Это удобно, когда нужно получить несколько независимых данных (список инструментов, ресурсы, результаты промптов и т.д.) и хочется минимизировать задержку.
Создание пакета
Используйте client.batch(), чтобы получить BatchBuilder, добавьте нужные запросы цепочкой и вызовите .send():
use neva::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Error> {
let mut client = Client::new()
.with_options(|opt| opt.with_default_http());
client.connect().await?;
let responses = client
.batch()
.list_tools()
.list_resources()
.call_tool("add", [("a", 40_i32), ("b", 2_i32)])
.send()
.await?;
println!("{responses:?}");
client.disconnect().await
}
send() возвращает Vec<Response> в том же порядке, в котором были добавлены запросы.
Доступные методы пакета
| Метод | Эквивалент одиночного вызова |
|---|---|
.list_tools() | client.list_tools(None) |
.call_tool(name, args) | client.call_tool(name, args) |
.list_resources() | client.list_resources(None) |
.read_resource(uri) | client.read_resource(uri) |
.list_resource_templates() | client.list_resource_templates(None) |
.list_prompts() | client.list_prompts(None) |
.get_prompt(name, args) | client.get_prompt(name, args) |
.ping() | client.ping() |
.notify(method, params) | уведомление без ожидания ответа |
Обработка ответов
Каждый элемент возвращаемого Vec<Response> соответствует запросу по порядку. Используйте into_result::<T>() для десериализации ответа в нужный тип:
let responses = client
.batch()
.list_tools()
.call_tool("add", [("a", 40_i32), ("b", 2_i32)])
.send()
.await?;
let tools = responses[0].clone().into_result::<ListToolsResult>()?;
let add = responses[1].clone().into_result::<CallToolResponse>()?;
println!("Инструменты: {:?}", tools.tools);
println!("add(40, 2) = {:?}", add.content);
Деструктуризация по шаблону
Для пакета фиксированного размера можно деструктурировать срез напрямую:
let responses = client
.batch()
.list_tools()
.list_resources()
.list_prompts()
.call_tool("add", [("a", 40_i32), ("b", 2_i32)])
.read_resource("notes://daily")
.get_prompt("greeting", [("name", "Neva")])
.ping()
.send()
.await?;
let [tools, resources, prompts, add_result, daily, greeting, ping] =
responses.as_slice() else {
return Err(Error::new(ErrorCode::InternalError, "неожиданное количество ответов"));
};
let tools = tools.clone().into_result::<ListToolsResult>()?;
let add = add_result.clone().into_result::<CallToolResponse>()?;
let daily = daily.clone().into_result::<ReadResourceResult>()?;
let greeting = greeting.clone().into_result::<GetPromptResult>()?;
Уведомления в пакете
Уведомления отправляются без ожидания ответа — они включаются в запрос, но не порождают слот в возвращаемом Vec:
use serde_json::json;
let responses = client
.batch()
.notify("notifications/message", Some(json!({ "level": "info", "data": "hello" })))
.list_tools()
.send()
.await?;
// responses содержит 1 элемент (только list_tools вернул ответ)
let tools = responses[0].clone().into_result::<ListToolsResult>()?;
На стороне сервера
Никакой дополнительной настройки сервера не требуется. Любой Neva-сервер — на транспортах stdio и HTTP — обрабатывает пакетные запросы JSON-RPC 2.0 автоматически.
Стандартной конфигурации достаточно:
use neva::prelude::*;
#[tokio::main]
async fn main() {
App::new()
.with_options(|opt| opt.with_default_http())
.run()
.await;
}
Обучение на примерах
Полный пример доступен здесь.