"""Thread-safe active-run steering primitives. Steering is deliberately separate from the normal per-session message queue. An instruction is accepted only while exactly one run for the scoped session is active; idle sessions never start a new run as a side effect. """ from __future__ import annotations import threading from collections import deque from dataclasses import dataclass from enum import Enum from typing import Deque, Dict, List, Optional, Set class SteerStatus(str, Enum): ACCEPTED = "accepted" INACTIVE = "inactive" AMBIGUOUS = "ambiguous" INVALID = "invalid" FULL = "full" CLOSING = "closing" @dataclass(frozen=True) class SteerResult: status: SteerStatus @property def accepted(self) -> bool: return self.status == SteerStatus.ACCEPTED class SteerInbox: """Bounded inbox owned by one active agent run.""" def __init__(self, max_pending: int = 16, max_chars: int = 8000): self.max_pending = max(1, int(max_pending)) self.max_chars = max(1, int(max_chars)) self._lock = threading.Lock() self._pending: Deque[str] = deque() self._accepting = True def submit(self, instruction: str) -> SteerResult: text = (instruction or "").strip() if not text or len(text) > self.max_chars: return SteerResult(SteerStatus.INVALID) with self._lock: if not self._accepting: return SteerResult(SteerStatus.CLOSING) if len(self._pending) >= self.max_pending: return SteerResult(SteerStatus.FULL) self._pending.append(text) return SteerResult(SteerStatus.ACCEPTED) def drain(self) -> List[str]: with self._lock: items = list(self._pending) self._pending.clear() return items def close_if_empty(self) -> bool: """Atomically stop accepting when no instruction is pending. This closes the race between a final empty drain and an agent run returning: after this method succeeds, submitters receive CLOSING. """ with self._lock: if self._pending: return False self._accepting = False return True def close(self) -> None: with self._lock: self._accepting = False class SteerRegistry: """Map a scoped agent/session key to its active run inboxes.""" def __init__(self): self._lock = threading.Lock() self._by_session: Dict[str, Set[SteerInbox]] = {} def register(self, session_id: str, inbox: Optional[SteerInbox] = None) -> SteerInbox: inbox = inbox or SteerInbox() if not session_id: return inbox with self._lock: self._by_session.setdefault(session_id, set()).add(inbox) return inbox def unregister(self, session_id: str, inbox: Optional[SteerInbox]) -> None: if not session_id or inbox is None: return inbox.close() with self._lock: bucket = self._by_session.get(session_id) if bucket is None: return bucket.discard(inbox) if not bucket: self._by_session.pop(session_id, None) def submit(self, session_id: str, instruction: str) -> SteerResult: if not (instruction or "").strip(): return SteerResult(SteerStatus.INVALID) with self._lock: inboxes = list(self._by_session.get(session_id, ())) if not inboxes: return SteerResult(SteerStatus.INACTIVE) if len(inboxes) != 1: return SteerResult(SteerStatus.AMBIGUOUS) return inboxes[0].submit(instruction) def active_count(self, session_id: str) -> int: with self._lock: return len(self._by_session.get(session_id, ())) _registry = SteerRegistry() def get_steer_registry() -> SteerRegistry: return _registry