diff --git a/apps/events.py b/apps/events.py index efa06cfda..01f36716e 100644 --- a/apps/events.py +++ b/apps/events.py @@ -29,14 +29,14 @@ Handlers receive an EventContext with: - ctx.app: The app name that owns this handler - ctx.tract: Event tract (e.g., "observe") - ctx.event: Event type (e.g., "observed") - - ctx.journal_root: Path to the journal directory + +Handlers can access journal path via `from convey import state` then `state.journal_root`. """ from __future__ import annotations import importlib import logging -import os from concurrent.futures import Future, ThreadPoolExecutor, TimeoutError from dataclasses import dataclass from pathlib import Path @@ -59,7 +59,6 @@ class EventContext: app: str tract: str event: str - journal_root: str # Handler registry: (tract, event) -> [(app_name, handler_fn), ...] @@ -270,7 +269,6 @@ def dispatch(msg: Dict[str, Any], timeout: float = DEFAULT_TIMEOUT) -> int: tract = msg.get("tract", "") event = msg.get("event", "") - journal_root = os.environ.get("JOURNAL_PATH", "") futures: List[Tuple[str, str, Future]] = [] @@ -280,7 +278,6 @@ def dispatch(msg: Dict[str, Any], timeout: float = DEFAULT_TIMEOUT) -> int: app=app_name, tract=tract, event=event, - journal_root=journal_root, ) future = _executor.submit(_run_handler, app_name, handler, ctx) futures.append((app_name, handler.__name__, future)) diff --git a/apps/remote/tests/test_events.py b/apps/remote/tests/test_events.py index fc57c3d45..d3347fc92 100644 --- a/apps/remote/tests/test_events.py +++ b/apps/remote/tests/test_events.py @@ -21,8 +21,7 @@ def remote_journal(tmp_path, monkeypatch): journal = tmp_path / "journal" journal.mkdir() - # Set JOURNAL_PATH env var and convey state - monkeypatch.setenv("JOURNAL_PATH", str(journal)) + # Set convey state (used by apps.utils for storage paths) monkeypatch.setattr(state, "journal_root", str(journal)) # Create remotes directory @@ -71,7 +70,6 @@ class TestHandleObserved: app="remote", tract="observe", event="observed", - journal_root=str(remote_journal.journal), ) handle_observed(ctx) @@ -106,7 +104,6 @@ class TestHandleObserved: app="remote", tract="observe", event="observed", - journal_root=str(remote_journal.journal), ) handle_observed(ctx) @@ -137,7 +134,6 @@ class TestHandleObserved: app="remote", tract="observe", event="observed", - journal_root=str(remote_journal.journal), ) handle_observed(ctx) @@ -159,7 +155,6 @@ class TestHandleObserved: app="remote", tract="observe", event="observed", - journal_root=str(remote_journal.journal), ) handle_observed(ctx) @@ -180,7 +175,6 @@ class TestHandleObserved: app="remote", tract="observe", event="observed", - journal_root=str(remote_journal.journal), ) # Should not raise @@ -202,7 +196,6 @@ class TestHandleObserved: app="remote", tract="observe", event="observed", - journal_root=str(remote_journal.journal), ) # Should not raise diff --git a/docs/APPS.md b/docs/APPS.md index db89050dc..9e30ff917 100644 --- a/docs/APPS.md +++ b/docs/APPS.md @@ -329,11 +329,21 @@ Define server-side handlers that react to Callosum events. Handlers run in Conve **Key Points:** - Create `events.py` with functions decorated with `@on_event(tract, event)` -- Handlers receive an `EventContext` with message data and app context +- Handlers receive an `EventContext` with `msg`, `app`, `tract`, `event` fields - Discovered at Convey startup; events processed serially with 30s timeout per handler - Errors are logged but don't affect other handlers or the web server - Wildcards supported: `@on_event("*", "*")` matches all events +**Available imports** (same as route handlers): +- `from convey import state` - Access `state.journal_root` +- `from convey import emit` - Emit events back to Callosum +- `from apps.utils import get_app_storage_path, log_app_action` - App storage +- `from convey.utils import load_json, save_json, spawn_agent` - Utilities + +**Not available** (no Flask request context): +- `request`, `session`, `current_app` +- `error_response()`, `success_response()`, `parse_pagination_params()` + **Reference implementations:** - Framework: `apps/events.py` - `EventContext` dataclass, decorator, discovery - Example: `apps/dev/events.py` - Debug handler showing usage pattern diff --git a/tests/test_app_events.py b/tests/test_app_events.py index 2ab8f07c7..2255099bf 100644 --- a/tests/test_app_events.py +++ b/tests/test_app_events.py @@ -4,8 +4,6 @@ """Tests for the app event handling framework.""" import threading -import time -from unittest.mock import patch import pytest @@ -225,22 +223,6 @@ class TestDispatch: # Second handler should still run despite first failing assert success_called.wait(timeout=2.0) - def test_dispatch_with_journal_root(self): - """Dispatch passes journal root from environment.""" - received_root = {} - - @on_event("test", "event") - def handler(ctx): - received_root["value"] = ctx.journal_root - - start_dispatcher(workers=1) - - with patch.dict("os.environ", {"JOURNAL_PATH": "/test/journal"}): - dispatch({"tract": "test", "event": "event"}) - time.sleep(0.1) - - assert received_root["value"] == "/test/journal" - class TestDiscovery: """Tests for handler discovery.""" @@ -264,14 +246,12 @@ class TestEventContext: app="test_app", tract="test", event="event", - journal_root="/path/to/journal", ) assert ctx.msg["data"] == "value" assert ctx.app == "test_app" assert ctx.tract == "test" assert ctx.event == "event" - assert ctx.journal_root == "/path/to/journal" class TestDispatcherLifecycle: