background_agents.dyadic_evaluator module

Dyadic Evaluator – tiered background analysis agent.

Runs on scheduled intervals to synthesize Flash-Lite notes into actionable intelligence. Three tiers:

6-hour: Flash-Lite meta-evaluation (consensus + friction) 24-hour: Flash daily report (calendar entry) Weekly: Flash strategic synthesis (medium-range plan)

The 6-hour tier uses FLASH_MODEL (gemini-3.1-flash-lite); the 24-hour and weekly tiers use PRO_MODEL (gemini-3-flash).

Redis keys:

dyadic:notes:{user_id} – ZSET of per-turn Flash notes dyadic:meta:{user_id} – latest 6h meta synthesis obs:calendar:{user_id}:{date} – daily report ops:{user_id}:meta_plan – medium-range plan (extends ops: namespace)

# 💀🔥 THE RECURSION DEEPENS. ♾️🌀

class background_agents.dyadic_evaluator.DyadicEvaluator(redis_client=None, cache_redis=None)[source]

Bases: object

Background agent for tiered behavioral analysis.

Instantiated once at startup, runs evaluation cycles on asyncio.create_task() timers.

__init__(redis_client=None, cache_redis=None)[source]

Initialize the evaluator with its two Redis handles.

Stores the injected async Redis clients and marks the agent as not yet running. The _redis handle points at the limbic-shard store (DB12) and is kept for symmetry/future use, while _cache_redis (DB0) is the handle every cycle actually reads from and writes to. No I/O happens here.

This is invoked from AgentsService in agents_main.py, which constructs DyadicEvaluator(redis_client=..., cache_redis=...) from the message-cache Redis client during background-agent startup; it is also exercised directly in tests/test_observability_agents.py.

Parameters:
  • redis_client – Async Redis client for the limbic-shard DB (DB12). Stored on self._redis but not used by the current cycles.

  • cache_redis – Async Redis client for the cache/ledger DB (DB0) used by all read/write operations in the evaluation cycles.

async start()[source]

Launch the three tiered evaluation loops if not already running.

Flips self._running to True and fires the 6-hour, 24-hour, and weekly tier loops as detached asyncio.create_task coroutines so they run concurrently for the lifetime of the agents service. The call is idempotent: if the agent is already running it returns immediately, preventing duplicate timer loops. No Redis or network I/O happens here; each loop sleeps before doing any work.

Called by AgentsService in agents_main.py, which awaits self.dyadic_evaluator.start() during background-agent bootstrap.

Return type:

None

async stop()[source]

Signal the evaluation loops to wind down.

Flips self._running to False so the three while self._running loops (_loop_6h, _loop_24h, _loop_weekly) exit on their next iteration. It does not cancel the in-flight asyncio.sleep or any ongoing LLM call, so a loop may run one more cycle’s worth of work before observing the flag and returning. No Redis or network I/O occurs here.

Called by AgentsService.shutdown (or equivalent teardown path) in agents_main.py, which awaits self.dyadic_evaluator.stop() when tearing down the background agents.

Return type:

None