Merge branch 'simp/r3-26-H' into simp/integration3

This commit is contained in:
Teknium
2026-09-02 23:11:37 -07:00
11 changed files with 46 additions and 79 deletions
+1 -3
View File
@@ -40,9 +40,7 @@ def _load_engine_from_dir(engine_dir: Path) -> Optional["ContextEngine"]: # noq
mod = _loader.load_plugin_module(
f"plugins.context_engine.{name}", engine_dir,
parents=("plugins", "plugins.context_engine"), logger=logger)
if mod is None:
return None
return _loader.instance_from_module(
return mod and _loader.instance_from_module(
mod, collector=_EngineCollector(engine_name=name), collected_attr="engine",
base_cls=ContextEngine, name=name, logger=logger)
+3 -6
View File
@@ -53,9 +53,8 @@ def find_provider_dir(name: str) -> Optional[Path]:
if bundled.is_dir() and (bundled / "__init__.py").exists():
return bundled
user_dir = _loader.user_plugins_dir()
if user_dir and (user_dir / name).is_dir() and _is_cron_provider_dir(user_dir / name):
return user_dir / name
return None
user = user_dir / name if user_dir else None
return user if user and user.is_dir() and _is_cron_provider_dir(user) else None
def discover_cron_schedulers() -> List[Tuple[str, str, bool]]:
@@ -85,9 +84,7 @@ def _load_provider_from_dir(provider_dir: Path) -> Optional["CronScheduler"]: #
mod = _loader.load_plugin_module(
module_name, provider_dir, parents=("plugins", "plugins.cron_providers"), logger=logger,
synthetic_namespace=None if is_bundled else _USER_NAMESPACE)
if mod is None:
return None
return _loader.instance_from_module(
return mod and _loader.instance_from_module(
mod, collector=_ProviderCollector(), collected_attr="provider",
base_cls=CronScheduler, name=name, logger=logger)
+2 -3
View File
@@ -7,6 +7,7 @@
from __future__ import annotations
import contextlib
import logging
import re
import shlex
@@ -38,10 +39,8 @@ def _extract_paths_from_terminal(args: Dict[str, Any], result: str) -> Set[str]:
paths: Set[str] = set()
cmd = args.get("command") or ""
if isinstance(cmd, str) and cmd:
try: # tokenise — catches `touch /tmp/hermes-x/test_foo.py`
with contextlib.suppress(ValueError): # tokenise — catches `touch /tmp/hermes-x/test_foo.py`
paths.update(tok for tok in shlex.split(cmd, posix=True) if tok.startswith(("/", "~")))
except ValueError:
pass
# Only scan the result text if it's a reasonable size (avoid 50KB dumps).
if isinstance(result, str) and len(result) < 4096:
paths.update(_TERMINAL_PATH_REGEX.findall(result))
+3 -6
View File
@@ -8,6 +8,7 @@ Scope: strictly HERMES_HOME and /tmp/hermes-*; never ~/.hermes/logs/ or system d
from __future__ import annotations
import contextlib
import json
import logging
import shutil
@@ -37,11 +38,9 @@ def _state_file(name: str) -> Path:
def is_safe_path(path: Path) -> bool:
"""Accept only paths under HERMES_HOME or ``/tmp/hermes-*`` (rejects /mnt/c etc.)."""
try:
with contextlib.suppress(ValueError, OSError):
path.resolve().relative_to(get_hermes_home())
return True
except (ValueError, OSError):
pass
parts = path.parts
return len(parts) >= 3 and parts[1] == "tmp" and parts[2].startswith("hermes-")
@@ -284,13 +283,11 @@ def _sweep_empty_dirs(hermes_home: Path) -> int:
while stack:
dirpath, visited = stack.pop()
if visited:
try:
with contextlib.suppress(OSError):
if not any(dirpath.iterdir()):
dirpath.rmdir()
removed += 1
_log(f"DELETED: {dirpath} (empty dir)")
except OSError:
pass
continue
stack.append((dirpath, True))
stack.extend((child, False) for child in _subdirs(dirpath, _EMPTY_DIR_SWEEP_PRUNE_DIRS))
+2 -3
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import contextlib
import json
from pathlib import Path
from typing import Any, Optional
@@ -24,8 +25,6 @@ def write_json_atomic(path: Path, data: Any, mode: Optional[int] = None) -> None
tmp = path.with_suffix(".json.tmp")
tmp.write_text(json.dumps(data, indent=2), encoding="utf-8")
if mode is not None:
try:
with contextlib.suppress(OSError, NotImplementedError): # best-effort on non-POSIX filesystems
tmp.chmod(mode)
except (OSError, NotImplementedError): # best-effort on non-POSIX filesystems
pass
tmp.replace(path)
+7 -15
View File
@@ -7,6 +7,7 @@ Linux: pactl creates a null-sink plus a virtual source on the sink's monitor; ca
from __future__ import annotations
import contextlib
import platform
import subprocess
from typing import Optional
@@ -29,7 +30,6 @@ class AudioBridge:
self._device_name: Optional[str] = None
self._write_target: Optional[str] = None
self._module_ids: list[int] = []
self._torn_down = False
def _ready(self, value: Optional[str]) -> str:
if not value:
@@ -46,29 +46,21 @@ class AudioBridge:
return self._setup_linux()
if system == "Darwin":
return self._setup_darwin()
if system == "Windows":
raise RuntimeError("windows not supported in v2")
raise RuntimeError(f"unsupported platform: {system}")
raise RuntimeError("windows not supported in v2" if system == "Windows"
else f"unsupported platform: {system}")
def teardown(self) -> None:
"""Release the virtual audio device. Idempotent; never raises."""
if self._torn_down:
return
if self._platform == "linux":
for mod_id in reversed(self._module_ids): # virtual-source before null-sink
try:
_pactl("unload-module", str(mod_id), check=False)
except Exception:
pass
self._module_ids = []
self._torn_down = True
for mod_id in reversed(self._module_ids): # linux only; virtual-source before null-sink
with contextlib.suppress(Exception):
_pactl("unload-module", str(mod_id), check=False)
self._module_ids = []
def _finish(self, tag: str, device: str, write_target: str, module_ids: list[int]) -> dict:
self._platform = tag
self._device_name = device
self._write_target = write_target
self._module_ids = module_ids
self._torn_down = False
return {"platform": tag, "device_name": device, "sample_rate": 48000, "channels": 2,
"module_ids": list(module_ids), "write_target": write_target}
+4 -4
View File
@@ -10,6 +10,7 @@
from __future__ import annotations
import argparse
import contextlib
import importlib.util
import json
import platform
@@ -213,17 +214,16 @@ def _cmd_auth() -> int:
return 1
path = _auth_state_path()
path.parent.mkdir(parents=True, exist_ok=True)
print(f"opening Chromium — sign in to Google, then return here and press Enter.\nsaving storage state to: {path}")
print("opening Chromium — sign in to Google, then return here and press Enter.\n"
f"saving storage state to: {path}")
try:
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://accounts.google.com/", wait_until="domcontentloaded")
try:
with contextlib.suppress(EOFError):
input("press Enter after you've signed in ... ")
except EOFError:
pass
context.storage_state(path=str(path))
browser.close()
except Exception as e:
+9 -15
View File
@@ -72,18 +72,12 @@ def validate_request(msg: Dict[str, Any], expected_token: str) -> Tuple[bool, st
"""Return ``(True, "")`` or ``(False, <reason>)``; reasons are safe to send back to the client."""
if not isinstance(msg, dict):
return False, "envelope must be a dict"
t = msg.get("type")
if not _nonempty_str(t):
return False, "missing or non-string 'type'"
if t not in VALID_REQUEST_TYPES:
return False, f"unknown request type: {t!r}"
if not _nonempty_str(msg.get("id")):
return False, "missing or non-string 'id'"
token = msg.get("token")
if not _nonempty_str(token):
return False, "missing token"
if token != expected_token:
return False, "token mismatch"
if not isinstance(msg.get("payload"), dict):
return False, "payload must be a dict"
return True, ""
t, token = msg.get("type"), msg.get("token")
checks = ( # ordered, lazily evaluated: first failing check wins
(lambda: _nonempty_str(t), "missing or non-string 'type'"),
(lambda: t in VALID_REQUEST_TYPES, f"unknown request type: {t!r}"),
(lambda: _nonempty_str(msg.get("id")), "missing or non-string 'id'"),
(lambda: _nonempty_str(token), "missing token"),
(lambda: token == expected_token, "token mismatch"),
(lambda: isinstance(msg.get("payload"), dict), "payload must be a dict"))
return next(((False, reason) for ok, reason in checks if not ok()), (True, ""))
+5 -7
View File
@@ -8,6 +8,7 @@ across turns can find the bot. The bot is a detached subprocess reached via file
from __future__ import annotations
import contextlib
import json
import os
import signal
@@ -47,10 +48,8 @@ def _active_pid() -> int:
def _kill(pid: int, sig) -> None:
try:
with contextlib.suppress(ProcessLookupError):
os.kill(pid, sig)
except ProcessLookupError:
pass
_NO_ACTIVE = {"ok": False, "reason": "no active meeting"}
@@ -72,10 +71,8 @@ def start(url: str, *, out_dir: Optional[Path] = None, headed: bool = False,
out.mkdir(parents=True, exist_ok=True)
# Wipe stale files from a previous run of this meeting id.
for name in ("transcript.txt", "status.json"):
try:
with contextlib.suppress(OSError):
(out / name).unlink()
except OSError:
pass
env = {**os.environ, "HERMES_MEET_URL": url, "HERMES_MEET_OUT_DIR": str(out),
"HERMES_MEET_GUEST_NAME": guest_name}
for value, var in (
@@ -149,7 +146,8 @@ def enqueue_say(text: str) -> Dict[str, Any]:
entry = {"id": uuid.uuid4().hex[:12], "text": text}
with queue_path.open("a", encoding="utf-8") as f:
f.write(json.dumps(entry) + "\n")
return {"ok": True, "meetingId": active.get("meeting_id"), "enqueued_id": entry["id"], "queue_path": str(queue_path)}
return {"ok": True, "meetingId": active.get("meeting_id"), "enqueued_id": entry["id"],
"queue_path": str(queue_path)}
def stop(*, reason: str = "requested") -> Dict[str, Any]:
+8 -14
View File
@@ -7,6 +7,7 @@ Chrome's fake mic. One sync WebSocket per session; ``websockets`` is imported la
from __future__ import annotations
import base64
import contextlib
import json
import threading
import time
@@ -69,10 +70,8 @@ class RealtimeSession:
def close(self) -> None:
if self._ws is not None:
try:
with contextlib.suppress(Exception):
self._ws.close()
except Exception:
pass
self._ws = None
def speak(self, text: str, timeout: float = 30.0) -> dict:
@@ -87,18 +86,16 @@ class RealtimeSession:
})
self._send_json({"type": "response.create", "response": {"modalities": ["audio"]}})
bytes_written = 0
sink_fp = None
if self.audio_sink_path is not None:
self.audio_sink_path.parent.mkdir(parents=True, exist_ok=True)
sink_fp = open(self.audio_sink_path, "ab")
try:
with contextlib.ExitStack() as stack:
sink_fp = None
if self.audio_sink_path is not None:
self.audio_sink_path.parent.mkdir(parents=True, exist_ok=True)
sink_fp = stack.enter_context(open(self.audio_sink_path, "ab"))
while True:
frame = self._recv_frame(start + timeout, timeout)
if frame is None: # connection closed by peer
if frame is None or frame.get("type") in _TERMINAL_FRAMES: # peer closed / response done
break
ftype = frame.get("type")
if ftype in _TERMINAL_FRAMES:
break
if ftype == "error":
raise RuntimeError(f"realtime error: {frame.get('error') or frame}")
if ftype == "response.audio.delta" and sink_fp is not None:
@@ -109,9 +106,6 @@ class RealtimeSession:
bytes_written += len(chunk)
self.audio_bytes_out += len(chunk)
self.last_audio_out_at = time.time()
finally:
if sink_fp is not None:
sink_fp.close()
return {"ok": True, "bytes_written": bytes_written, "duration_ms": (time.monotonic() - start) * 1000.0}
def cancel_response(self) -> bool:
+2 -3
View File
@@ -5,6 +5,7 @@ or an ABC-subclass fallback."""
from __future__ import annotations
import contextlib
import importlib.machinery
import importlib.util
import logging
@@ -150,10 +151,8 @@ def instance_from_module(mod: Any, *, collector: Any, collected_attr: str, base_
for attr_name in dir(mod):
attr = getattr(mod, attr_name, None)
if isinstance(attr, type) and issubclass(attr, base_cls) and attr is not base_cls:
try:
with contextlib.suppress(Exception):
return attr()
except Exception:
pass
return None