
Negotiation.pudu
Pudu58 lines2.3 KB
1/** @Domain.Protocol.Negotiation.Backbone — admits requests by protocol era */2module PuduLangMcp.Domain.Protocol.Negotiation34import Std.Json as Json5import Std.Text as Text6import PuduLangMcp.Constants.Protocol as Protocol7import PuduLangMcp.Errors.RpcError as RpcError8import PuduLangMcp.Utils.JsonAccess as Access910/** @Domain.Protocol.Negotiation.Session — the only process-scoped protocol state */11export type Session = Unopened | Legacy(Str)1213/** @Domain.Protocol.Negotiation.Era — version governing one admitted request */14export type Era = Modern | LegacyEra(Str)151617const HANDSHAKE: Str = "initialize"181920export fn isHandshake(method: Str) -> Bool {21 method == HANDSHAKE22}232425export fn admit(session: &Session, method: Str, params: &Json.Json) -> Result[Era, RpcError.ProtocolError] {26 let meta = match Access.member(params, Protocol.META_KEY) {27 case Some(Json.Object(fields)) => Json.Object(fields)28 case _ => Json.object(&[])29 }30 match Access.member(&meta, Protocol.META_PROTOCOL_VERSION) {31 case Some(Json.Text(requested)) => {32 if requested != Protocol.MODERN_VERSION {33 return Err(RpcError.UnsupportedVersion(requested))34 }35 match Access.member(&meta, Protocol.META_CLIENT_CAPABILITIES) {36 case Some(Json.Object(_)) => Ok(Modern)37 case _ => Err(RpcError.InvalidParams("_meta must include " + Protocol.META_CLIENT_CAPABILITIES + " as an object"))38 }39 }40 case Some(_) => Err(RpcError.InvalidParams(Protocol.META_PROTOCOL_VERSION + " must be a string"))41 case None => {42 if isHandshake(method) { return Ok(LegacyEra(negotiateLegacy(params))) }43 match session {44 case Legacy(version) => Ok(LegacyEra(version))45 case Unopened => Err(RpcError.InvalidParams("missing _meta " + Protocol.META_PROTOCOL_VERSION + "; send " + Protocol.MODERN_VERSION + " on every request, or call initialize first for " + Text.join(&Protocol.LEGACY_VERSIONS, ", ")))46 }47 }48 }49}505152export fn negotiateLegacy(params: &Json.Json) -> Str {53 match Access.text(params, "protocolVersion") {54 case Some(asked) => if Protocol.isLegacyVersion(asked) { asked } else { Protocol.LATEST_LEGACY_VERSION }55 case None => Protocol.LATEST_LEGACY_VERSION56 }57}58