[eric] backend: final leading-_ cleanup, file-local shorts + move session cancel-event to manager-side table (off the pydantic model, kills the last underscore); naming linter now 0/0

This commit is contained in:
ciregenz
2026-06-23 21:57:20 -07:00
parent 1bcc78567b
commit 6ab6217ac7
9 changed files with 32 additions and 25 deletions
+4
View File
@@ -82,6 +82,10 @@ class AgentManager(SessionLifecycleMixin, SessionPersistenceMixin, MessagingMixi
# stop can persist the partial reply instantly instead of waiting out the
# multi-second SDK teardown the cancel handler sits behind.
self.live_partial: Dict[str, LivePartial] = {}
# Per-session cancel signal: the loop stashes its asyncio.Event here so a
# stop/close can set it. Lives on the manager, not the AgentSession model,
# so it stays out of serialization (an Event can't be model_dump'd).
self.cancel_events: Dict[str, asyncio.Event] = {}
+1 -1
View File
@@ -375,7 +375,7 @@ async def run_browser_agent(
system_prompt=SYSTEM_PROMPT,
parent_session_id=parent_session_id,
)
session._cancel_event = cancel_event
agent_manager.cancel_events[session_id] = cancel_event
agent_manager.sessions[session_id] = session
# If parent was already stopped before we registered, bail immediately
@@ -31,8 +31,9 @@ class SessionControlMixin:
if session:
# Set cancel event BEFORE cancelling the task so in-flight
# browser agent loops see it immediately
if hasattr(session, '_cancel_event'):
session._cancel_event.set()
ev = self.cancel_events.get(session_id)
if ev:
ev.set()
for req in list(session.pending_approvals):
ws_manager.resolve_approval(req.id, {"behavior": "deny", "message": "Agent stopped"})
@@ -69,8 +69,9 @@ class SessionLifecycleMixin:
ws_manager.resolve_approval(req.id, {"behavior": "deny", "message": "Session closed"})
session.pending_approvals = []
if hasattr(session, '_cancel_event'):
session._cancel_event.set()
ev = self.cancel_events.get(session_id)
if ev:
ev.set()
self.sync_session_close(session)
@@ -103,6 +104,7 @@ class SessionLifecycleMixin:
self.sessions.pop(session_id, None)
self.tasks.pop(session_id, None)
self.live_partial.pop(session_id, None)
self.cancel_events.pop(session_id, None)
view_builder_render_retry_counts.pop(session_id, None)
view_builder_dirty_sessions.discard(session_id)
@@ -69,8 +69,8 @@ WEBAPP_TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "webapp_template")
# Bundled default; used as the read-once fallback if the user-editable
# copy at ~/.claude/skills/app_builder_skill.md has been removed despite
# the built-in flag (defensive; shouldn't happen in normal use).
with open(APP_BUILDER_SKILL_SOURCE_PATH, encoding="utf-8") as _f:
APP_BUILDER_SKILL_DEFAULT = _f.read()
with open(APP_BUILDER_SKILL_SOURCE_PATH, encoding="utf-8") as p_f:
APP_BUILDER_SKILL_DEFAULT = p_f.read()
def load_app_builder_skill() -> str:
+6 -6
View File
@@ -38,14 +38,14 @@ class MainApp:
p_boot_t0 = time.perf_counter()
for sub_app in sub_apps:
debug(sub_app.name)
_t0 = time.perf_counter()
p_t0 = time.perf_counter()
await stack.enter_async_context(sub_app.lifespan())
_dt = (time.perf_counter() - _t0) * 1000
if _dt > 50: # only flag a slow lifespan; keeps boot logs quiet
print(f"[perf] lifespan {sub_app.name} t={_dt:.0f}ms", flush=True)
p_dt = (time.perf_counter() - p_t0) * 1000
if p_dt > 50: # only flag a slow lifespan; keeps boot logs quiet
print(f"[perf] lifespan {sub_app.name} t={p_dt:.0f}ms", flush=True)
print(f"[perf] lifespans-total t={(time.perf_counter() - p_boot_t0) * 1000:.0f}ms", flush=True)
_port = os.environ.get("OPENSWARM_PORT", "8324")
print(f"\nCheck out the API docs at: http://127.0.0.1:{_port}/docs\n")
p_port = os.environ.get("OPENSWARM_PORT", "8324")
print(f"\nCheck out the API docs at: http://127.0.0.1:{p_port}/docs\n")
yield
self.app = FastAPI(lifespan=lifespan)
+8 -8
View File
@@ -8,21 +8,21 @@ import uuid
from backend.config.paths import DATA_ROOT
P_INSTALL_ID_FILE = os.path.join(DATA_ROOT, "install_id")
_cached: str | None = None
p_cached: str | None = None
def get_install_id() -> str:
"""Return the persistent install_id, generating and persisting on first call."""
global _cached
if _cached:
return _cached
global p_cached
if p_cached:
return p_cached
try:
with open(P_INSTALL_ID_FILE, "r", encoding="utf-8") as f:
existing = f.read().strip()
if p_looks_like_uuid(existing):
_cached = existing
return _cached
p_cached = existing
return p_cached
except FileNotFoundError:
pass
except Exception:
@@ -35,8 +35,8 @@ def get_install_id() -> str:
os.write(fd, fresh.encode("utf-8"))
finally:
os.close(fd)
_cached = fresh
return _cached
p_cached = fresh
return p_cached
def p_looks_like_uuid(s: str) -> bool:
+3 -3
View File
@@ -10,9 +10,9 @@ from uuid import uuid4
# handlers; uvicorn's own access logs are untouched.
p_backend_logger = logging.getLogger("backend")
if not p_backend_logger.handlers:
_h = logging.StreamHandler()
_h.setFormatter(logging.Formatter("%(asctime)s %(levelname).1s %(name)s: %(message)s", "%H:%M:%S"))
p_backend_logger.addHandler(_h)
p_h = logging.StreamHandler()
p_h.setFormatter(logging.Formatter("%(asctime)s %(levelname).1s %(name)s: %(message)s", "%H:%M:%S"))
p_backend_logger.addHandler(p_h)
p_backend_logger.setLevel(logging.INFO)
p_backend_logger.propagate = False
+1 -1
View File
@@ -132,7 +132,7 @@ async def test_arm_with_no_sub_is_bounded_and_falls_through_to_arm(monkeypatch):
monkeypatch.setattr(ft, "p_has_connected_subscription", never_sub)
# Short-circuit before the cloud mint so the test stays offline + deterministic;
# reaching this branch proves arm did NOT falsely conclude has_model.
monkeypatch.setattr(ft, "p_fingerprint", lambda _s: None)
monkeypatch.setattr(ft, "p_fingerprint", lambda p_s: None)
s = AppSettings()
t = time.monotonic()