agents_main

Agents service entry point — scheduled background work and agents.

Runs AgentsService, a StargazerService dedicated to recurring/background jobs so they never compete with the latency-sensitive Inference workers. It owns the cluster-singleton TaskSupervisor (leader-elected via a Redis lock, so exactly one instance runs each cron job) and schedules tasks through a BackgroundScheduler, including:

  • Knowledge-graph maintenance: auto KG extraction, agentic bulk incremental extraction, and channel summarization.

  • Limbic/NCM upkeep: maintenance, dedup, anchoring, sunset, and the journal stream.

  • Scheduled prompt ticks/cleanup and Gemini key probing.

It also boots optional background agents (DyadicEvaluator, GameArtAgent, GameTurnAgent), the SWORD subsystem (sword.factory.build_sword_system()), and the StarWiki service, and persists embeddings asynchronously via EmbeddingBatchQueue.

Launched standalone (python agents_main.py) by scripts/systemd/stargazer-agents.service.

class agents_main.AgentsService(config, redis_client, instance_id)[source]

Bases: StargazerService

Background-work microservice running scheduled jobs and agents.

Concrete StargazerService for the agents tier. It isolates recurring/LLM-heavy work (KG extraction, limbic upkeep, journaling, key probing, channel summarization) from the latency-sensitive inference workers by owning a leader-elected TaskSupervisor and a BackgroundScheduler, plus optional background agents (dyadic evaluator, game art/turn agents), the SWORD subsystem and StarWiki.

Instances are constructed by main() (and by the migration tests under tests/core/migration/); the base class drives the lifecycle by calling on_start(), run() and on_stop() from boot/shutdown.

Parameters:
__init__(config, redis_client, instance_id)[source]

Initialize the agents service and declare its component slots.

Wires up the base StargazerService with service_name="agents" and a required Redis client, then sets every heavyweight collaborator (message cache, KG manager, OpenRouter client, supervisor, embedding queue, event bus, background agents) to None so they can be lazily built in on_start(). The BackgroundScheduler is the only collaborator constructed eagerly here.

Interactions: calls super().__init__ on StargazerService (which may create a HealthServer) and constructs a BackgroundScheduler. No Redis or network I/O happens at construction time.

Called by main() when booting the standalone process, and directly by the migration tests in tests/core/migration/ that exercise the service in isolation.

Parameters:
  • config (Config) – Loaded application configuration supplying Redis, OpenRouter/Gemini, model and feature-flag settings; stored as self.cfg.

  • redis_client (Any) – Async Redis client (decoded responses off) used for service registration, the supervisor lock and scheduled tasks.

  • instance_id (str) – Unique id for this process (e.g. agents-<hex>) used for service registration, the event-bus node id and the supervisor’s leader-election identity.

get_adapter(platform_name)[source]

Return a proxy platform adapter that sends via the event bus.

Builds a ProxyPlatformAdapter bound to this service’s RedisEventBus so background agents can emit outbound platform actions (messages, etc.) without owning a real platform connection; the inference/gateway tier consumes those events and performs the actual send.

Interactions: constructs a fresh ProxyPlatformAdapter over self.event_bus each call (no caching). The bus must already be initialized in on_start(); calling this before on_start yields an adapter over a None bus.

Called by on_start() to obtain the "discord" adapter for the GameArtAgent and GameTurnAgent, and by the agents migration tests; mirrors the get_adapter method on the inference and web services.

Parameters:

platform_name (str) – Logical platform key (e.g. "discord") the adapter will tag its outbound events with.

Returns:

Event-bus-backed adapter for platform_name.

Return type:

ProxyPlatformAdapter

async on_start()[source]

Build collaborators and register all scheduled and supervised work.

Implements the abstract on_start of StargazerService. Constructs the OpenRouterClient, MessageCache, KnowledgeGraphManager, EmbeddingBatchQueue, RedisEventBus and TaskSupervisor, then registers the supervised limbic_dedup_worker and a fleet of periodic jobs on the BackgroundScheduler (prompt tick/cleanup, auto and agentic-bulk KG extraction, channel summarization, optional log RAG ingest, Gemini key probe, limbic maintenance/anchoring/sunset, journal stream, anamnesis digest, and — when enabled — StarWiki). Finally it starts the supervisor and scheduler, kicks off SWORD bootstrap in the background, and starts the optional dyadic/game agents.

Interactions: resolves SSL/connection kwargs from Config; calls set_observability_redis from observability; awaits embedding_queue.start(), event_bus.ensure_streams(), supervisor.start() and scheduler.start(); builds the SWORD system via sword.factory.build_sword_system() and, in a fire-and-forget asyncio.create_task() (_bootstrap_sword), ensures SWORD indexes and loads Origin fragments from system_prompt.j2 before attaching the monitor to the KG manager. Conditionally constructs and starts StarwikiService, DyadicEvaluator, GameArtAgent and GameTurnAgent (the latter two over the "discord" adapter from get_adapter()); agent startup failures are logged and swallowed so one failing agent cannot abort boot. Mutates the instance attributes declared in __init__().

Called by StargazerService.boot (Phase 3-7) after the Redis connection is verified; never invoked directly outside the migration tests.

Raises:

Exception – Propagates failures from core collaborator construction or the awaited start/ensure_streams calls (which would abort boot); per-agent and SWORD-bootstrap errors are caught and logged instead.

Return type:

None

async run()[source]

Block forever so scheduled jobs and agents keep running.

Implements the abstract run loop of StargazerService. The agents service does no per-tick work in the foreground — the supervisor, scheduler and background agents started in on_start() drive everything — so this simply awaits a never-set asyncio.Event until the task is cancelled at shutdown.

Interactions: awaits asyncio.Event().wait(); swallows the asyncio.CancelledError raised when the process is shutting down so cancellation unwinds cleanly.

Called by main() after service.boot() completes; cancellation is triggered by the SIGINT/SIGTERM handlers installed in main(), which invoke service.shutdown().

Return type:

None

async on_stop()[source]

Tear down the scheduler, supervisor, agents and clients in order.

Implements the abstract on_stop cleanup of StargazerService, releasing everything stood up in on_start(). It stops the scheduler and supervisor first (halting new task launches and releasing the leader lock), then the game turn/art agents and dyadic evaluator, then the embedding queue, and finally closes the OpenRouter client.

Interactions: awaits scheduler.stop() and supervisor.shutdown(); best-effort awaits stop() on GameTurnAgent, GameArtAgent, DyadicEvaluator and EmbeddingBatchQueue (each wrapped in try/except so one failure cannot block the rest), then awaits openrouter.close(). Each component is guarded by a truthiness check so partial-boot states shut down safely.

Called by StargazerService.shutdown after service deregistration; shutdown itself is invoked by the signal handlers wired in main().

Return type:

None

async agents_main.main()[source]

Configure, boot and run the agents service as a standalone process.

Process entry point: sets up basic logging, loads Config, mints an agents-<hex> instance id, builds an async Redis client and constructs an AgentsService. It installs SIGINT/SIGTERM handlers that schedule a graceful service.shutdown(), then boots and runs the service until cancellation, closing the Redis client in a finally block.

Interactions: calls Config.load() and cfg.build_async_redis_client(decode_responses=False); registers signal handlers on the running event loop that call service.shutdown(); awaits service.boot() (which runs on_start()) and service.run(); guarantees redis_client.aclose() on exit.

Called by the if __name__ == "__main__" guard via asyncio.run() (launched by scripts/systemd/stargazer-agents.service) and is patched/awaited directly by the migration tests in tests/core/migration/test_service_entrypoints.py.

Return type:

None