diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 2a51c17..416add3 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -40,6 +40,7 @@ This makes the code easy to modify from a terminal or by an agent. models.py Session model + CRUD, per-session profile tracking (~137 lines) profiles.py Profile state management, hermes_cli wrapper (~246 lines) routes.py All GET + POST route handlers (~1180 lines) + startup.py Startup helpers: auto_install_agent_deps() (~50 lines) streaming.py SSE engine, run_agent, cancel, HERMES_HOME save/restore (~236 lines) upload.py Multipart parser, file upload handler (~78 lines) workspace.py File ops: list_dir, read_file_content, workspace helpers (~77 lines) diff --git a/server.py b/server.py index eb3ddba..009422d 100644 --- a/server.py +++ b/server.py @@ -12,6 +12,7 @@ from api.auth import check_auth from api.config import HOST, PORT, STATE_DIR, SESSION_DIR, DEFAULT_WORKSPACE from api.helpers import j from api.routes import handle_get, handle_post +from api.startup import auto_install_agent_deps class Handler(BaseHTTPRequestHandler): @@ -75,7 +76,16 @@ def main() -> None: print(f'[!!] Warning: Hermes agent found but missing modules: {missing}', flush=True) for mod, err in errors.items(): print(f' {mod}: {err}', flush=True) - print(' Agent features may not work correctly.', flush=True) + print(' Attempting to install missing dependencies from agent requirements.txt...', flush=True) + auto_install_agent_deps() + ok, missing, errors = verify_hermes_imports() + if not ok: + print(f'[!!] Still missing after install attempt: {missing}', flush=True) + for mod, err in errors.items(): + print(f' {mod}: {err}', flush=True) + print(' Agent features may not work correctly.', flush=True) + else: + print('[ok] Agent dependencies installed successfully.', flush=True) STATE_DIR.mkdir(parents=True, exist_ok=True) SESSION_DIR.mkdir(parents=True, exist_ok=True) diff --git a/tests/conftest.py b/tests/conftest.py index 0960193..452c013 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -210,6 +210,18 @@ def test_server(): Start an isolated test server on TEST_PORT with a clean state directory. Paths are discovered dynamically -- no hardcoded absolute path assumptions. """ + # Kill any leftover process on the test port before starting. + # Stale servers from QA harness runs or prior test sessions cause + # conftest to think the server is already up, producing false failures. + try: + import subprocess as _sp + _sp.run(['fuser', '-k', f'{TEST_PORT}/tcp'], + capture_output=True, timeout=5) + except Exception: + pass + import time as _time + _time.sleep(0.5) # brief pause to let the port release + # Clean slate if TEST_STATE_DIR.exists(): shutil.rmtree(TEST_STATE_DIR)