From cd3f3c89ed4bd759e26a5fe0d153392c1a304e59 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 23 Feb 2026 16:23:55 -0500 Subject: [PATCH] feat(events): Add EventEmitter and instrument ai_client.py --- ai_client.py | 4 ++++ events.py | 14 ++++++++++++++ tests/test_api_events.py | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 events.py create mode 100644 tests/test_api_events.py diff --git a/ai_client.py b/ai_client.py index 586ab70..bdad941 100644 --- a/ai_client.py +++ b/ai_client.py @@ -19,6 +19,7 @@ from pathlib import Path import file_cache import mcp_client import google.genai +from events import EventEmitter _provider: str = "gemini" _model: str = "gemini-2.5-flash" @@ -27,6 +28,9 @@ _max_tokens: int = 8192 _history_trunc_limit: int = 8000 +# Global event emitter for API lifecycle events +events = EventEmitter() + def set_model_params(temp: float, max_tok: int, trunc_limit: int = 8000): global _temperature, _max_tokens, _history_trunc_limit _temperature = temp diff --git a/events.py b/events.py new file mode 100644 index 0000000..3368692 --- /dev/null +++ b/events.py @@ -0,0 +1,14 @@ + +class EventEmitter: + def __init__(self): + self._listeners = {} + + def on(self, event_name, callback): + if event_name not in self._listeners: + self._listeners[event_name] = [] + self._listeners[event_name].append(callback) + + def emit(self, event_name, *args, **kwargs): + if event_name in self._listeners: + for callback in self._listeners[event_name]: + callback(*args, **kwargs) diff --git a/tests/test_api_events.py b/tests/test_api_events.py new file mode 100644 index 0000000..f5f6635 --- /dev/null +++ b/tests/test_api_events.py @@ -0,0 +1,20 @@ + +import pytest +from unittest.mock import MagicMock +import ai_client + +def test_ai_client_event_emitter_exists(): + # This should fail initially because 'events' won't exist on ai_client + assert hasattr(ai_client, 'events') + assert ai_client.events is not None + +def test_event_emission(): + # We'll expect these event names based on the spec + mock_callback = MagicMock() + ai_client.events.on("request_start", mock_callback) + + # Trigger something that should emit the event (once implemented) + # For now, we just test the emitter itself if we were to call it manually + ai_client.events.emit("request_start", payload={"model": "test"}) + + mock_callback.assert_called_once_with(payload={"model": "test"})