1"""In-memory inference logger for LLM routing.
2
3Stores a bounded FIFO queue of ``InferenceLog`` entries in memory.
4Suitable for development and single-process deployments. State is lost
5on process restart; use ``DatabaseInferenceLogger`` for production.
6"""
7
8from __future__ import annotations
9
10import asyncio
11from typing import TYPE_CHECKING
12
13from lexigram.logging import (
14 get_logger,
15)
16
17if TYPE_CHECKING:
18 from lexigram.ai.llm.routing.types import InferenceLog
19
20logger = get_logger(__name__)
21
22__all__ = ["InMemoryInferenceLogger"]
23
24
25class InMemoryInferenceLogger:
26 """Bounded FIFO in-memory inference logger.
27
28 Stores up to *max_size* ``InferenceLog`` entries. When the limit is
29 reached, the oldest entry is evicted before inserting the new one
30 (FIFO eviction).
31
32 Example:
33 >>> inference_logger = InMemoryInferenceLogger(max_size=500)
34 >>> await inference_logger.log(some_log)
35 >>> recent = await inference_logger.get_recent(limit=10)
36 """
37
38 def __init__(self, max_size: int = 1000) -> None:
39 """Initialise the in-memory inference logger.
40
41 Args:
42 max_size: Maximum number of log entries to retain.
43 """
44 self._max_size = max_size
45 self._entries: list[InferenceLog] = []
46 self._lock = asyncio.Lock()
47
48 async def log(self, entry: InferenceLog) -> None:
49 """Record one ``InferenceLog`` entry.
50
51 Evicts the oldest entry when ``max_size`` is reached.
52
53 Args:
54 entry: :class:`~lexigram.ai.llm.routing.types.InferenceLog` instance.
55 """
56 async with self._lock:
57 if len(self._entries) >= self._max_size:
58 self._entries.pop(0)
59 self._entries.append(entry)
60
61 async def get_recent(self, limit: int = 100) -> list[InferenceLog]:
62 """Return the most recent *limit* log entries (newest-first).
63
64 Args:
65 limit: Maximum number of entries to return.
66
67 Returns:
68 Reversed slice of the internal list (newest first).
69 """
70 async with self._lock:
71 return list(reversed(self._entries[-limit:]))