Skip to content

Public API

wspkit re-exports everything you need for the programmatic flow from the top-level package.

from wspkit import (
    # Lifecycle / capabilities
    Capabilities,
    PROTOCOL_VERSION,
    # Endpoint data models
    DeleteAck,
    Environment,
    ExecuteResult,
    Package,
    # Error model
    DuplicateRegistrationError,
    JsonRpcErrorCode,
    ProtocolError,
    WspError,
    WspErrorCode,
    # JSON-RPC types (advanced)
    JsonRpcError,
    JsonRpcRequest,
    JsonRpcResponse,
    # Registry
    Handler,
    HandlerRegistry,
    # Server runtime
    run_stdio,
)

Registry

HandlerRegistry is the source of truth mapping WSP method names to the Python callables that service them. Both the programmatic flow and the Config_File flow funnel through HandlerRegistry.register.

class HandlerRegistry:
    def register(self, method: str, handler: Handler) -> None: ...
    def methods(self) -> list[str]: ...               # sorted
    def lookup(self, method: str) -> Handler | None: ...

Handler is Callable[[Any], Awaitable[Any] | Any]. Sync handlers run on the default executor; async handlers are awaited directly.

register raises DuplicateRegistrationError if the method already has a binding, leaving prior state unchanged.

Server runtime

async def run_stdio(
    registry: HandlerRegistry,
    *,
    transport: StdioTransport | None = None,
    drain_timeout: float = 5.0,
) -> int: ...

Returns the desired process exit status. Wrap in asyncio.run from a script.

Error types

class WspError(ProtocolError):
    """Application-level error in the -31999..-31000 reserved range."""

    def __init__(
        self,
        code: int,
        message: str,
        data: Any | None = None,
    ) -> None: ...

code must lie in the WSP-reserved range (-31999 to -31000). message must be non-empty; messages longer than 500 characters are truncated with a trailing ellipsis. data, when provided, must be JSON-serializable.

ProtocolError is the base class for any handler exception that should map directly to a JSON-RPC error response. A ProtocolError that isn't also a WspError (i.e. carries no WSP code) is remapped to -31004 EXECUTION_FAILED by the dispatcher.

class JsonRpcErrorCode(IntEnum):
    PARSE_ERROR = -32700
    INVALID_REQUEST = -32600
    METHOD_NOT_FOUND = -32601
    INVALID_PARAMS = -32602
    INTERNAL_ERROR = -32603
    SERVER_NOT_INITIALIZED = -32002


class WspErrorCode(IntEnum):
    ENVIRONMENT_NOT_FOUND = -31001
    ENVIRONMENT_NAME_CONFLICT = -31002
    PYTHON_VERSION_UNAVAILABLE = -31003
    EXECUTION_FAILED = -31004

Endpoint data models

@dataclass(frozen=True)
class Capabilities:
    methods: tuple[str, ...]
    protocol_version: str = PROTOCOL_VERSION  # "0.1.0"

    def to_jsonable(self) -> dict[str, Any]: ...
    @classmethod
    def from_jsonable(cls, value: Any) -> Capabilities: ...


@dataclass(frozen=True)
class Environment:
    id: str
    name: str
    python_version: str
    interpreter_path: str | None = None
    installed_packages: tuple[Package, ...] | None = None
    extra: Mapping[str, Any] | None = None

    @property
    def is_details(self) -> bool: ...
    def to_jsonable(self) -> dict[str, Any]: ...
    @classmethod
    def from_jsonable(cls, value: Any) -> Environment: ...

Environment represents both the summary form (only id, name, python_version) and the details form. to_jsonable omits the detail-only fields when they're None; from_jsonable accepts either shape.

@dataclass(frozen=True)
class Package:
    name: str
    version: str


@dataclass(frozen=True)
class ExecuteResult:
    exit_code: int
    stdout: str
    stderr: str


@dataclass(frozen=True)
class DeleteAck:
    id: str

All four dataclasses expose to_jsonable and from_jsonable helpers.

JSON-RPC types

@dataclass(frozen=True)
class JsonRpcRequest:
    method: str
    params: Any | None
    id: str | int | None
    is_notification: bool


@dataclass(frozen=True)
class JsonRpcError:
    code: int
    message: str
    data: Any = _UNSET   # omitted on the wire when unset


@dataclass(frozen=True)
class JsonRpcResponse:
    id: str | int | None
    result: Any = _UNSET
    error: Any = _UNSET   # mutually exclusive with result

Most users won't need these directly; they're exposed for tools that want to construct or inspect JSON-RPC messages without going through the codec.

Stability

The above surface is the supported public API for the 0.1.x line. Anything not listed here — including the dispatcher and lifecycle internals — may change between patch releases.