from __future__ import annotations import dataclasses import enum class PrincipalType(enum.StrEnum): """Kinds of authenticated principals accepted by LangBot.""" ACCOUNT = 'account' API_KEY = 'api_key' SUPPORT_ADMIN = 'support_admin' SYSTEM = 'system' PUBLIC_BOT = 'public_bot' @dataclasses.dataclass(frozen=True, slots=True) class PrincipalContext: """Authenticated identity before Workspace authorization is applied.""" principal_type: PrincipalType account_uuid: str | None = None actor_account_uuid: str | None = None api_key_uuid: str | None = None support_session_id: str | None = None @dataclasses.dataclass(frozen=True, slots=True) class WorkspaceContext: """Workspace membership and effective permissions for one request.""" workspace_uuid: str membership_uuid: str | None role: str | None permissions: frozenset[str] membership_revision: int = 0 @dataclasses.dataclass(frozen=True, slots=True) class RequestContext: """Trusted authorization context passed to HTTP services.""" instance_uuid: str placement_generation: int request_id: str auth_type: str principal: PrincipalContext workspace: WorkspaceContext entitlement_revision: int = 0 @property def workspace_uuid(self) -> str: """Return the selected Workspace UUID.""" return self.workspace.workspace_uuid @property def account_uuid(self) -> str | None: """Return the Account UUID when the principal is an Account.""" return self.principal.account_uuid @dataclasses.dataclass(frozen=True, slots=True) class ExecutionContext: """Workspace context propagated to asynchronous and runtime work.""" instance_uuid: str workspace_uuid: str placement_generation: int bot_uuid: str | None = None pipeline_uuid: str | None = None query_uuid: str | None = None trigger_principal: PrincipalContext | None = None entitlement_revision: int = 0 @classmethod def from_request( cls, ctx: RequestContext, *, bot_uuid: str | None = None, pipeline_uuid: str | None = None, query_uuid: str | None = None, ) -> ExecutionContext: """Create a runtime context without losing the tenant generation.""" return cls( instance_uuid=ctx.instance_uuid, workspace_uuid=ctx.workspace_uuid, placement_generation=ctx.placement_generation, bot_uuid=bot_uuid, pipeline_uuid=pipeline_uuid, query_uuid=query_uuid, trigger_principal=ctx.principal, entitlement_revision=ctx.entitlement_revision, )