Ctrl K
ComunidadGuías…

butler/gateway/locked_turn_orchestrator.py

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

Archivo original ↗Preguntar a KiBot
"""In-session locked turn orchestrator (ENG-3 / ENG-11)."""

from __future__ import annotations

import logging
import time as _time
from typing import TYPE_CHECKING, cast
from butler.gateway.locked_phases import LockedTurnState
from butler.gateway.owner_delegate_shortcuts import resolve_project_context, try_expand_owner_edit_slash
from butler.gateway.owner_ingest_shortcuts import try_expand_owner_ingest_phrase
from butler.gateway.handler_helpers import _maybe_welcome_prefix
from butler.gateway.locked_phase_registry import run_augment_phase, run_pre_lock_phases
from butler.execution_context import use_execution_context
from butler.gateway.locked_turn_orchestrator_ops import run_in_context_phases_or_fail

if TYPE_CHECKING:
    from butler.gateway.message_handler import ButlerMessageHandler
    from butler.gateway.locked_phases import LockedTurnState

logger = logging.getLogger(__name__)


def expand_owner_shortcuts(handler: "ButlerMessageHandler", state: "LockedTurnState") -> None:
    """Owner natural-language → slash expansions before normalizers run."""

    assert isinstance(state, LockedTurnState)
    pname, pws = resolve_project_context(handler._orchestrator, state.session_key)
    expanded = try_expand_owner_edit_slash(state.text, project_name=pname)
    if expanded:
        state.text = expanded
        return
    ingest = try_expand_owner_ingest_phrase(
        state.text,
        project_name=pname,
        workspace=pws,
    )
    if ingest:
        state.text = ingest


def run_locked_message_turn(
    handler: ButlerMessageHandler,
    text: str,
    *,
    session_key: str = "default",
    platform: str = "unknown",
    external_id: str | None = None,
) -> str:
    """Execute the in-session pipeline under the per-session lock."""

    if not text.strip():
        return ""

    state = LockedTurnState(
        text=text,
        session_key=session_key,
        platform=platform,
        external_id=external_id,
    )
    welcome_prefix = _maybe_welcome_prefix(session_key, text)

    expand_owner_shortcuts(handler, state)

    response = run_pre_lock_phases(handler, state)
    if response is not None:
        return cast(str, response)

    state.turn_started = _time.monotonic()
    logger.info(
        "Gateway turn start session=%s platform=%s preview=%r",
        session_key,
        platform,
        text[:80],
    )

    with use_execution_context(handler._orchestrator, session_key=session_key):
        run_augment_phase(handler, state)
        state.loop = handler._get_or_create_loop(session_key)
        state.original_loop_config = state.loop.config

        try:
            result, err = run_in_context_phases_or_fail(
                handler,
                state,
                welcome_prefix=welcome_prefix,
                session_key=session_key,
            )
            if err is not None:
                return cast(str, err)
            return cast(str, result if result is not None else state.out)
        finally:
            state.loop.config = state.original_loop_config


__all__ = ["expand_owner_shortcuts", "run_locked_message_turn"]