- harness/es.py: append-only event store + проекции (образец — кооп-портал) - harness/levels.py: уровни 1с/1м/1ч/1д, контекст ∝ масштабу - harness/scheduler.py: уровневые потоки, идемпотентные тики, absorbed-стабы - harness/isolated_runner.py + _llm_worker.py: LLM-тик в сабпроцессе (глобальный asyncio-рантайм Strands не переживает 2+ create_harness) - cli.py: init/task/tasks/status/events + requeue (написан самим минутным агентом) - 9router: отдельный ключ sk-simbiot, модель auto (glm-5.3 первым)
83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import threading
|
|
from typing import Any, Callable
|
|
|
|
EventHandler = Callable[..., Any]
|
|
|
|
|
|
class EventHandlerRegistry:
|
|
"""Thread-safe (optional) registry of event handlers."""
|
|
|
|
def __init__(self, *, use_lock: bool = False) -> None:
|
|
self._handlers: dict[str, list[EventHandler]] = {}
|
|
self._once_ids: set[int] = set()
|
|
self._lock: threading.Lock | None = threading.Lock() if use_lock else None
|
|
|
|
def _acquire(self) -> None:
|
|
if self._lock is not None:
|
|
self._lock.acquire()
|
|
|
|
def _release(self) -> None:
|
|
if self._lock is not None:
|
|
self._lock.release()
|
|
|
|
def add(self, event_type: str, handler: EventHandler, *, once: bool = False) -> None:
|
|
self._acquire()
|
|
try:
|
|
handlers = self._handlers.setdefault(event_type, [])
|
|
handlers.append(handler)
|
|
if once:
|
|
self._once_ids.add(id(handler))
|
|
finally:
|
|
self._release()
|
|
|
|
def remove(self, event_type: str, handler: EventHandler) -> None:
|
|
self._acquire()
|
|
try:
|
|
handlers = self._handlers.get(event_type)
|
|
if handlers is not None:
|
|
try:
|
|
handlers.remove(handler)
|
|
except ValueError:
|
|
pass
|
|
self._once_ids.discard(id(handler))
|
|
finally:
|
|
self._release()
|
|
|
|
def get_handlers(self, event_type: str) -> list[EventHandler]:
|
|
"""Return a snapshot of handlers for the given event type, removing once-handlers."""
|
|
self._acquire()
|
|
try:
|
|
handlers = self._handlers.get(event_type)
|
|
if not handlers:
|
|
return []
|
|
result = list(handlers)
|
|
to_remove = [h for h in result if id(h) in self._once_ids]
|
|
for h in to_remove:
|
|
handlers.remove(h)
|
|
self._once_ids.discard(id(h))
|
|
return result
|
|
finally:
|
|
self._release()
|
|
|
|
def has_handlers(self, event_type: str) -> bool:
|
|
self._acquire()
|
|
try:
|
|
handlers = self._handlers.get(event_type)
|
|
return bool(handlers)
|
|
finally:
|
|
self._release()
|
|
|
|
def merge_into(self, target: EventHandlerRegistry) -> None:
|
|
"""Move all handlers from this registry into *target*, then clear self."""
|
|
self._acquire()
|
|
try:
|
|
for event_type, handlers in self._handlers.items():
|
|
for handler in handlers:
|
|
once = id(handler) in self._once_ids
|
|
target.add(event_type, handler, once=once)
|
|
self._handlers.clear()
|
|
self._once_ids.clear()
|
|
finally:
|
|
self._release()
|