Ctrl K
ComunidadGuías…

butler/gateway/locked_phases/state.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
from __future__ import annotations

import logging
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, Callable, Optional

from butler.core.best_effort import safe_best_effort
from butler.core.loop_types import LoopCallbacks
from butler.gateway.handler_helpers import (
    _normalize_contacts_request,
    _normalize_detail_request,
    _normalize_expense_request,
    _normalize_habits_request,
    _normalize_memo_request,
    _normalize_new_session_request,
    _normalize_status_request,
    _normalize_switch_request,
)

if TYPE_CHECKING:
    pass

logger = logging.getLogger(__name__)


@dataclass
class LockedTurnState:
    """Mutable carrier for one in-session turn.

    Phases mutate fields on this object. The orchestrator is
    responsible for initializing inputs and reading the final
    ``out`` after the run.
    """

    text: str
    session_key: str
    platform: str
    external_id: str | None
    loop_role: str = ""
    health: dict[str, Any] = field(default_factory=dict)
    augmented: str = ""
    ephemeral_system: Optional[str] = None
    prompt_hooks: Any = None
    loop: Any = None
    original_loop_config: Any = None
    max_out: Optional[int] = None
    run_callbacks: Any = None
    result: Any = None
    out: str = ""
    turn_started: float = 0.0
    turn_elapsed: float = 0.0
    session_read_recall_gate: bool = False
    local_project_inventory_gate: bool = False


def _load_normalizers() -> tuple[Callable[[str], Optional[str]], ...]:
    return (
        _normalize_detail_request,
        _normalize_switch_request,
        _normalize_status_request,
        _normalize_new_session_request,
        _normalize_memo_request,
        _normalize_contacts_request,
        _normalize_expense_request,
        _normalize_habits_request,
    )


def _chain_callbacks(base: Any, extra: Any) -> Any:
    if base is None:
        return extra
    if extra is None:
        return base

    def _chain(name: str) -> Any:
        fn_a = getattr(base, name, None)
        fn_b = getattr(extra, name, None)
        if fn_a is None:
            return fn_b
        if fn_b is None:
            return fn_a

        def chained(*args: Any, **kwargs: Any) -> Any:
            safe_best_effort(
                lambda: fn_a(*args, **kwargs),
                label="locked_phases.callback_chain",
            )
            return safe_best_effort(
                lambda: fn_b(*args, **kwargs),
                label="locked_phases.callback_chain",
                default=None,
            )

        return chained

    return LoopCallbacks(**{
        f.name: _chain(f.name) for f in LoopCallbacks.__dataclass_fields__.values()
    })