Source code for gestalt._api

"""Core request, response, and model helpers for authored operations."""

from __future__ import annotations

import dataclasses
from dataclasses import MISSING
from http import HTTPStatus
from typing import TYPE_CHECKING, Any, Final, Generic, TypeVar

if TYPE_CHECKING:
    from typing_extensions import dataclass_transform
else:
    try:
        from typing import dataclass_transform
    except ImportError:
        try:
            from typing_extensions import dataclass_transform
        except ImportError:

            def dataclass_transform(*args: Any, **kwargs: Any):
                def decorator(cls: type[Any]) -> type[Any]:
                    return cls

                return decorator


if TYPE_CHECKING:
    from ._agent import AgentManager
    from ._authorization import AuthorizationClient
    from ._invoker import PluginInvoker
    from ._workflow import WorkflowManager

FIELD_DESCRIPTION_KEY: Final[str] = "description"
FIELD_REQUIRED_KEY: Final[str] = "required"

T = TypeVar("T")


[docs] @dataclasses.dataclass(slots=True) class Subject: """Identity information attached to an incoming provider request.""" id: str = "" kind: str = "" display_name: str = "" auth_source: str = ""
[docs] @dataclasses.dataclass(slots=True) class Credential: """Credential metadata resolved by the Gestalt host for the request.""" mode: str = "" subject_id: str = "" connection: str = "" instance: str = ""
[docs] @dataclasses.dataclass(slots=True) class Access: """Authorization context resolved for the request.""" policy: str = "" role: str = ""
[docs] @dataclasses.dataclass(slots=True) class Request: """Host-provided request context for an operation invocation.""" token: str = "" connection_params: dict[str, str] = dataclasses.field(default_factory=dict) subject: Subject = dataclasses.field(default_factory=Subject) credential: Credential = dataclasses.field(default_factory=Credential) access: Access = dataclasses.field(default_factory=Access) invocation_token: str = "" # Workflow callback metadata uses a JSON-style lowerCamelCase object such # as runId, target.plugin.pluginName, trigger.scheduleId, and # trigger.event.specVersion. workflow: dict[str, Any] = dataclasses.field(default_factory=dict) def connection_param(self, name: str) -> str | None: """Return a connection parameter by name if the host supplied it.""" return self.connection_params.get(name) def invoker(self) -> "PluginInvoker": from ._invoker import PluginInvoker return PluginInvoker(self.invocation_token) def agent_manager(self) -> "AgentManager": from ._agent import AgentManager return AgentManager(self.invocation_token) def workflow_manager(self) -> "WorkflowManager": from ._workflow import WorkflowManager return WorkflowManager(self.invocation_token) def authorization(self) -> "AuthorizationClient": from ._authorization import Authorization return Authorization()
[docs] @dataclasses.dataclass(slots=True) class Response(Generic[T]): """Structured operation response with an explicit HTTP status.""" status: int | None body: T
[docs] def OK(body: T) -> Response[T]: """Wrap ``body`` in a success response with status ``200 OK``.""" return Response(status=HTTPStatus.OK, body=body)
[docs] class Error(Exception): """Application error raised by a provider operation.""" def __init__(self, status: int | HTTPStatus, message: str = "") -> None: self.status = int(status) if message: self.message = message else: try: self.message = HTTPStatus(self.status).phrase except ValueError: self.message = "" super().__init__(self.message)
[docs] def field( *, description: str = "", default: Any = MISSING, default_factory: Any = MISSING, required: bool | None = None, ) -> Any: """Declare a model field with catalog metadata. Args: description: Human-readable parameter description exported to the generated catalog. default: Explicit default value for the field. default_factory: Callable used to create the default value. required: Override the inferred required flag in the generated catalog. """ metadata: dict[str, Any] = {} if description: metadata[FIELD_DESCRIPTION_KEY] = description if required is not None: metadata[FIELD_REQUIRED_KEY] = required kwargs: dict[str, Any] = {"metadata": metadata} if default is not MISSING: kwargs["default"] = default if default_factory is not MISSING: kwargs["default_factory"] = default_factory return dataclasses.field(**kwargs)
[docs] @dataclass_transform(field_specifiers=(field,)) class Model: """Base class for operation input and output models. Subclasses are automatically converted into dataclasses, so provider authors can declare request and response types with normal annotations: .. code-block:: python class SearchInput(Model): query: str = field(description="Search term") """ def __init_subclass__(cls, **kwargs: Any) -> None: super().__init_subclass__(**kwargs) if "__dataclass_fields__" not in cls.__dict__: dataclasses.dataclass(cls)