background_agents.game_art_agent module

Background art generation agent for S.N.E.S. game turns.

Consumes sg:stream:game:art through a Redis consumer group. 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, *, consumer_name='game-art-agent')

Bases: object

Background agent that auto-generates game art after each turn.

Listens on a durable Redis Stream for art requests enqueued 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)

  • consumer_name (str)

__init__(redis_client=None, platform_adapter=None, config=None, *, consumer_name='game-art-agent')

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 in start().

Constructed by the agents service bootstrap in agents_main.py.

Parameters:
  • redis_client (Any) – Async Redis client for stream events, durable image state, and session-flag reads. When None, start() becomes a no-op.

  • platform_adapter (Any) – Proxy adapter exposing durable file delivery.

  • config (Any) – Optional configuration object retained for downstream use.

  • consumer_name (str)

Return type:

None

async start()

Begin consuming durable art-request stream events.

Builds the sg:game-art:v1 consumer, using this service instance’s unique consumer name, and starts its reclaim/read/ACK loop. The call is a no-op if the agent is already running or no Redis client was injected.

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

Return type:

None

async stop()

Stop and await the durable stream-consumer task.

Return type:

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', event_id=None, raise_on_error=False)

Durably enqueue an art generation request for 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.

Return type:

dict[str, str] | None

Parameters:
  • redis (Any)

  • channel_id (str)

  • narrative (str)

  • character_urls (list[str] | None)

  • character_names (list[str] | None)

  • game_name (str)

  • aspect_ratio (str)

  • event_id (str | None)

  • raise_on_error (bool)