background_agents.game_art_agent module
Background art generation agent for S.N.E.S. game turns.
Subscribes to game:art:request Redis pub/sub channel.
When a game turn completes, the main pipeline publishes the
narrative + character image URLs. This agent generates art
via the Gemini image API and posts it directly to the channel
WITHOUT feeding the result back into the conversation context.
This eliminates the 400 INVALID_ARGUMENT errors caused by large tool results bloating the chat API payload.
# 💀🔥 ART DAEMON – RUNS OUTSIDE THE CONTEXT WINDOW
- class background_agents.game_art_agent.GameArtAgent(redis_client=None, platform_adapter=None, config=None)[source]
Bases:
objectBackground agent that auto-generates game art after each turn.
Listens on Redis pub/sub for art requests published by the main pipeline after game turn responses are sent. Generates images via Gemini and posts them directly to Discord.
This keeps the image generation result OUT of the LLM’s conversation history, preventing context overflow 400 errors.
- Parameters:
redis_client (Any)
platform_adapter (Any)
config (Any)
- __init__(redis_client=None, platform_adapter=None, config=None)[source]
Initialize the background art agent with its injected dependencies.
Stores the Redis client (used for pub/sub subscriptions and for reading Dark Loopmother session flags), the platform adapter (used by
_send_to_channel()to post the finished PNG to Discord), and the config object, and sets the running flag and pub/sub handle to their idle defaults. No I/O happens here; subscriptions begin instart().Constructed by the agents service bootstrap in
agents_main.py.- Parameters:
- Return type:
None
- async start()[source]
Begin listening for art requests and turn-complete events.
Marks the agent running, initializes the
_pending_turnsmap that tracks turns awaiting a fallback render, and launches two detachedasyncio.create_tasklisteners:_listen_loop(explicitgame:art:requestpub/sub) and_listen_turn_complete(thegame:turn:completebackup path). The call is a no-op if the agent is already running or no Redis client was injected, so it is safe to call once during bootstrap. No art is generated here; the listeners drive that.Called by
AgentsServiceinagents_main.py, which awaitsself.game_art_agent.start()during background-agent startup.- Return type:
- async stop()[source]
Stop the agent and tear down its art-request subscription.
Clears the running flag so the listener loops in
_listen_loop()and_listen_turn_complete()exit on their next iteration, then attempts to unsubscribe the primary pub/sub handle fromgame:art:request. Unsubscribe errors are swallowed so shutdown is best-effort. Note that thegame:turn:completefallback pub/sub created locally in_listen_turn_complete()is not explicitly unsubscribed here; it unwinds when that coroutine observes the cleared flag.Called during agents-service shutdown in
agents_main.py.- Return type:
- Returns:
None.
- async background_agents.game_art_agent.publish_art_request(redis, channel_id, narrative, character_urls=None, character_names=None, game_name='', aspect_ratio='16:9')[source]
Publish an art generation request to the background agent.
Call this from the main pipeline after a game turn response is sent. The background GameArtAgent will pick it up and generate art WITHOUT touching the conversation context.