///|
/// The closed set of typed results returned by stable Client-to-Agent
/// requests. Constructor names are prefixed so this reply union cannot be
/// confused with the corresponding request constructors.
pub(all) enum ClientReply {
ClientReplyInitialize(InitializeResult)
ClientReplyAuthenticate(AuthenticateResult)
ClientReplyLogout(LogoutResult)
ClientReplyNewSession(NewSessionResult)
ClientReplyLoadSession(LoadSessionResult)
ClientReplyResumeSession(ResumeSessionResult)
ClientReplyListSessions(ListSessionsResult)
ClientReplyDeleteSession(DeleteSessionResult)
ClientReplyCloseSession(CloseSessionResult)
ClientReplySetMode(SetSessionModeResult)
ClientReplySetConfigOption(SetSessionConfigOptionResult)
ClientReplyPrompt(PromptResult)
} derive(Eq, Debug)
///|
/// Return the exact request method associated with a typed reply.
pub fn ClientReply::method_name(self : ClientReply) -> String {
match self {
ClientReplyInitialize(_) => "initialize"
ClientReplyAuthenticate(_) => "authenticate"
ClientReplyLogout(_) => "logout"
ClientReplyNewSession(_) => "session/new"
ClientReplyLoadSession(_) => "session/load"
ClientReplyResumeSession(_) => "session/resume"
ClientReplyListSessions(_) => "session/list"
ClientReplyDeleteSession(_) => "session/delete"
ClientReplyCloseSession(_) => "session/close"
ClientReplySetMode(_) => "session/set_mode"
ClientReplySetConfigOption(_) => "session/set_config_option"
ClientReplyPrompt(_) => "session/prompt"
}
}
///|
/// Explicit failures crossing the Client-to-Agent typed connection facade.
/// Runtime adapters may return these values from negotiated capability gates
/// or transport cancellation; the facade never converts them into success.
pub(all) suberror ClientConnectionError {
ClientConnectionUnsupportedVersion(method_name~ : String, version~ : Int)
ClientConnectionUnavailable(method_name~ : String)
ClientConnectionCancelled(method_name~ : String)
ClientConnectionBrokerFailure(method_name~ : String)
ClientConnectionReplyMismatch(
method_name~ : String,
expected~ : String,
actual~ : String
)
} derive(Eq, Debug)
///|
/// Stable v1 exposes only protocol version 1. Reject an incompatible typed
/// request or broker result explicitly instead of silently negotiating a
/// version this facade cannot implement.
fn client_connection_require_v1(
method_name : String,
version : Int,
) -> Unit raise ClientConnectionError {
if version != 1 {
raise ClientConnectionUnsupportedVersion(method_name~, version~)
}
}
///|
/// A one-shot typed request transport. It owns no request identifiers or
/// connection state; those remain with the runtime that implements it.
pub type ClientRequestBroker = async (AgentRequest) -> Result[
ClientReply,
ClientConnectionError,
]
///|
/// A one-shot typed notification transport. Notifications have no reply,
/// and this facade deliberately keeps this port synchronous: a runtime may
/// accept the immutable notification intent into a bounded queue (or fail
/// fast); `Ok` does not claim that transport I/O has completed.
pub type ClientNotificationBroker = (AgentNotification) -> Result[
Unit,
ClientConnectionError,
]
///|
/// Opaque typed Client connection facade. Only immutable broker closures are
/// retained; no mutable protocol state, request-id table, capability flags,
/// queue, task, global, or service locator is stored here.
pub struct ClientConnection {
request_broker : ClientRequestBroker
notification_broker : ClientNotificationBroker
}
///|
/// Construct one immutable Client connection around caller-owned typed
/// transport ports. This is intentionally a one-shot constructor rather than
/// a builder or registration API.
pub fn client_connection(
request_broker~ : ClientRequestBroker,
notification_broker~ : ClientNotificationBroker,
) -> ClientConnection {
{ request_broker, notification_broker }
}
///|
async fn client_connection_request(
connection : ClientConnection,
request : AgentRequest,
method_name : String,
) -> ClientReply raise ClientConnectionError {
let result = try (connection.request_broker)(request) catch {
error =>
if @async.is_cancellation_error(error) {
Err(ClientConnectionCancelled(method_name~))
} else {
Err(ClientConnectionBrokerFailure(method_name~))
}
} noraise {
value => value
}
match result {
Ok(reply) => reply
Err(error) => raise error
}
}
///|
fn client_connection_notification(
connection : ClientConnection,
notification : AgentNotification,
) -> Unit raise ClientConnectionError {
match (connection.notification_broker)(notification) {
Ok(_) => ()
Err(error) => raise error
}
}
///|
pub async fn ClientConnection::initialize(
self : ClientConnection,
params : InitializeParams,
) -> InitializeResult raise ClientConnectionError {
client_connection_require_v1("initialize", params.protocol_version)
match client_connection_request(self, Initialize(params), "initialize") {
ClientReplyInitialize(result) => {
client_connection_require_v1("initialize", result.protocol_version)
result
}
reply =>
raise ClientConnectionReplyMismatch(
method_name="initialize",
expected="initialize",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::authenticate(
self : ClientConnection,
params : AuthenticateParams,
) -> AuthenticateResult raise ClientConnectionError {
match client_connection_request(self, Authenticate(params), "authenticate") {
ClientReplyAuthenticate(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="authenticate",
expected="authenticate",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::logout(
self : ClientConnection,
params : LogoutParams,
) -> LogoutResult raise ClientConnectionError {
match client_connection_request(self, Logout(params), "logout") {
ClientReplyLogout(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="logout",
expected="logout",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::new_session(
self : ClientConnection,
params : NewSessionParams,
) -> NewSessionResult raise ClientConnectionError {
match client_connection_request(self, SessionNew(params), "session/new") {
ClientReplyNewSession(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/new",
expected="session/new",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::load_session(
self : ClientConnection,
params : LoadSessionParams,
) -> LoadSessionResult raise ClientConnectionError {
match client_connection_request(self, SessionLoad(params), "session/load") {
ClientReplyLoadSession(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/load",
expected="session/load",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::resume_session(
self : ClientConnection,
params : ResumeSessionParams,
) -> ResumeSessionResult raise ClientConnectionError {
match
client_connection_request(self, SessionResume(params), "session/resume") {
ClientReplyResumeSession(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/resume",
expected="session/resume",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::list_sessions(
self : ClientConnection,
params : ListSessionsParams,
) -> ListSessionsResult raise ClientConnectionError {
match client_connection_request(self, SessionList(params), "session/list") {
ClientReplyListSessions(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/list",
expected="session/list",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::delete_session(
self : ClientConnection,
params : DeleteSessionParams,
) -> DeleteSessionResult raise ClientConnectionError {
match
client_connection_request(self, SessionDelete(params), "session/delete") {
ClientReplyDeleteSession(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/delete",
expected="session/delete",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::close_session(
self : ClientConnection,
params : CloseSessionParams,
) -> CloseSessionResult raise ClientConnectionError {
match client_connection_request(self, SessionClose(params), "session/close") {
ClientReplyCloseSession(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/close",
expected="session/close",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::set_mode(
self : ClientConnection,
params : SetSessionModeParams,
) -> SetSessionModeResult raise ClientConnectionError {
match
client_connection_request(self, SessionSetMode(params), "session/set_mode") {
ClientReplySetMode(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/set_mode",
expected="session/set_mode",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::set_config_option(
self : ClientConnection,
params : SetSessionConfigOptionParams,
) -> SetSessionConfigOptionResult raise ClientConnectionError {
match
client_connection_request(
self,
SessionSetConfigOption(params),
"session/set_config_option",
) {
ClientReplySetConfigOption(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/set_config_option",
expected="session/set_config_option",
actual=reply.method_name(),
)
}
}
///|
pub async fn ClientConnection::prompt(
self : ClientConnection,
params : PromptParams,
) -> PromptResult raise ClientConnectionError {
match
client_connection_request(self, SessionPrompt(params), "session/prompt") {
ClientReplyPrompt(result) => result
reply =>
raise ClientConnectionReplyMismatch(
method_name="session/prompt",
expected="session/prompt",
actual=reply.method_name(),
)
}
}
///|
/// Emit the stable `session/cancel` notification. No response is synthesized.
pub fn ClientConnection::cancel(
self : ClientConnection,
params : CancelParams,
) -> Unit raise ClientConnectionError {
client_connection_notification(self, SessionCancel(params))
}
///|
/// Emit the bidirectional JSON-RPC cancellation notification. Correlation
/// identifiers remain typed and are not converted through raw JSON.
pub fn ClientConnection::cancel_request(
self : ClientConnection,
request_id : RequestId,
) -> Unit raise ClientConnectionError {
client_connection_notification(self, CancelRequest(request_id))
}