"""Per-turn orchestration. A turn is: gather dynamic context, hand the conversation to the backend, return the response. As capabilities grow (memory recall, routing per intent, channel adapters) they hang off this function. """ from datetime import datetime from .context import build_turn_context from .models import Message, ModelRequest, call_model def handle_turn(messages: list[Message], user: str | None = None) -> str: #decorated = _decorate_latest_user(messages, user) request = ModelRequest( messages=messages, turn_context=build_turn_context(), ) response = call_model(request) return response.content def _decorate_latest_user(messages: list[Message], user: str | None) -> list[Message]: """Prepend [timestamp] [user: name] to the latest user message only. Older user messages keep their original form, they were already decorated at the time they were sent, and Open WebUI is feeding us back the conversation history including those decorations. """ if not messages: return messages # find the latest user message; decorate it decorated = list(messages) for i in range(len(decorated) - 1, -1, -1): if decorated[i].role == "user": now = datetime.now(timezone.utc).astimezone().isoformat(timespec="seconds") name = f"[user: {user}] " if user else "" prefix = f"[{now}] {name}" decorated[i] = Message( role="user", content=prefix + decorated[i].content, ) break return decorated