butler/gateway/locked_turn_orchestrator.py
Rama main · réplica de lectura del repositorio original.
"""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"]