API Module

The API module provides a high-level interface for building Neuro API game clients. This module builds upon the foundational client and command modules to offer a complete, abstract base class for game integration with the Neuro system.

Overview

The API module contains the main AbstractNeuroAPI class that game developers should inherit from to create their Neuro-integrated games. It handles action registration, command processing, and provides hooks for game-specific implementations. This module abstracts away much of the low-level command formatting and message handling.

Classes

NeuroAction

class neuro_api.api.NeuroAction(id_: str, name: str, data: str | None)

Representation of a Neuro Action with its associated details.

A NamedTuple that encapsulates the essential information for an action in the Neuro game interaction system.

id_

Unique identifier for the action. The trailing underscore is used to avoid conflicts with Python’s built-in id keyword.

Type:

str

name

Name of the action to be performed.

Type:

str

data

Optional additional data associated with the action. Can be None if no additional information is required.

Type:

str | None

A named tuple representing an action request from Neuro with all necessary details.

Attributes:

  • id_ (str): Unique identifier for the action (underscore avoids Python’s id keyword)

  • name (str): Name of the action to be performed

  • data (str | None): Optional JSON-stringified data for the action

Example:

action = NeuroAction(
    id_="action_123",
    name="move_player",
    data='{"direction": "north", "steps": 3}'
)
id_: str

Alias for field number 0

name: str

Alias for field number 1

data: str | None

Alias for field number 2

AbstractNeuroAPI

class neuro_api.api.AbstractNeuroAPI(game_title: str)

Abstract base class for the Neuro Game Interaction API.

Provides a foundational interface for managing game actions and interactions with the Neuro system. This class is designed to be subclassed by specific game implementations.

game_title

The title or name of the game being integrated.

Type:

str

Note

This is an abstract base class that requires implementation of specific game interaction methods in subclasses.

High-level abstract base class for Neuro API game clients.

This class provides a complete framework for integrating games with the Neuro system. It handles:

  • Action registration and management

  • Command processing and routing

  • Context communication with Neuro

  • Shutdown handling for automated games

  • Internal state tracking

Attributes:

  • game_title (str): The name of the integrated game

__init__(game_title: str) None

Initialize the Neuro API for a specific game.

Parameters:

game_title (str) – The name of the game to be integrated with the Neuro system.

Note

Initializes the internal action registry to track currently registered actions.

get_registered() tuple[str, ...]

Return the names of all currently registered actions.

Returns:

A tuple containing the names of all actions currently registered in the Neuro API.

Return type:

tuple[str, …]

Note

This method provides a snapshot of registered actions at the time of calling.

async send_startup_command() None

Send startup command to initialize the game with Neuro.

This method sends the initial message to the Neuro system when a game starts. It serves two critical purposes: - Inform Neuro that the game is now running - Clear and reset any previously registered actions

Note

This should be the very first message sent after game initialization.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the startup command.

Warning

Sends a command that clears all previously registered actions for this game, performing a complete action registry reset.

async send_context(message: str, silent: bool = True) None

Send a contextual message to Neuro about the game state.

Allows communication of game events or state information to Neuro without necessarily requiring an immediate response.

Parameters:
  • message (str) – A plaintext description of what is happening in the game. This information will be directly received by Neuro.

  • silent (bool, optional) –

    Controls Neuro’s response behaviour: - If True (default): Message is added to context silently

    without prompting a response.

    • If False: Neuro _might_ respond directly, unless she is busy talking to someone else or to chat.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the context command.

Note

This method provides a flexible way to keep Neuro informed about game events without disrupting ongoing interactions.

async register_actions(actions: list[Action]) None

Register a list of actions with Neuro.

Validates and registers multiple actions for Neuro to use during game interaction. This method performs two key operations: - Validates each action’s name and schema - Sends the actions to Neuro for registration

Parameters:

actions (list[command.Action]) – A list of actions to be registered. If an action is already registered, it will be ignored.

Raises:
  • ValueError – If any action: - Contains invalid characters in its name - Has an invalid schema key

  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action registration.

Note

  • Each action is validated before registration

  • Previously registered actions with the same name will not be overwritten

  • The method maintains an internal registry of registered actions

async unregister_actions(action_names: Sequence[str]) None

Unregister specified Neuro actions.

Removes actions from both the internal registry and Neuro’s action set, preventing these actions from being used in future interactions.

Parameters:

action_names (Sequence[str]) – The names of the actions to unregister. Attempting to unregister an action that isn’t registered will not cause any errors.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action unregistration.

Note

  • No error is raised for non-existent actions

async send_force_action(state: str, query: str, action_names: Sequence[str], ephemeral_context: bool = False, priority: ForcePriority = ForcePriority.LOW) None

Force Neuro to execute an action with specific context.

Sends a command to Neuro that compels her to choose and execute one of the specified actions, providing detailed game state and action instructions.

Parameters:
  • state (str) – An arbitrary string describing the current game state. Can be plaintext, JSON, Markdown, or any other format. This information will be directly received by Neuro.

  • query (str) – A plaintext message instructing Neuro on her current task (e.g., “It is now your turn. Please perform an action. If you want to use any items, you should use them before picking up the shotgun.”). This information will be directly received by Neuro.

  • action_names (Sequence[str]) – Names of actions Neuro can choose from during this force action.

  • ephemeral_context (bool, optional) –

    Controls context persistence: - If False (default): The state and query context will

    be remembered after actions force completion.

    • If True: Neuro will only remember the context during the actions force.

  • priority (command.ForcePriority) – Determines how urgently Neuro should respond to the action force when she is speaking. If Neuro is not speaking, this setting has no effect. The default is command.ForcePriority.LOW, which will cause Neuro to wait until she finishes speaking before responding. command.ForcePriority.MEDIUM causes her to finish her current utterance sooner. command.ForcePriority.HIGH prompts her to process the action force immediately, shortening her utterance and then responding. command.ForcePriority.CRITICAL will interrupt her speech and make her respond at once. Use command.ForcePriority.CRITICAL with caution, as it may lead to abrupt and potentially jarring interruptions.

Raises:
  • ValueError – If any specified action name is not currently registered.

  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action force command.

Warning

  • Neuro can only handle one action force at a time.

  • Sending an action force while another is in progress will cause problems.

async send_action_result(id_: str, success: bool, message: str | None = None) None

Report the result of a Neuro-initiated action.

Communicates the outcome of an action to Neuro, allowing her to proceed with her decision-making process. This method is critical for maintaining the flow of game interactions.

Parameters:
  • id (str) – The unique identifier of the action being reported. This ID is directly obtained from the original action message.

  • success (bool) –

    Indicates the action’s outcome: - If True: Action was successfully executed. - If False: Action failed. Note: If this action is part

    of an actions force, Neuro will immediately retry the entire actions force.

  • message (str, optional) –

    A descriptive message about the action’s execution: - For unsuccessful actions: Should be an error message. - For successful actions: Can be empty or provide a _small_

    context about the action (e.g., “Remember to not share this with anyone.”).

    This information will be directly received by Neuro.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action result.

Warning

  • Until an action result is sent, Neuro will be waiting and unable to proceed.

  • Send this method call as soon as possible after action validation, preferably before in-game execution.

Note

To prevent automatic retrying of a failed action: - Set success to True - Provide an error message in the message field

async send_shutdown_ready() None

Send shutdown ready response.

This is part of the game automation API, which will only be used for games that Neuro can launch by herself. As such, most games will not need to implement this.

This should be sent as a response to a graceful or an imminent shutdown request, after progress has been saved. After this is sent, Neuro will close the game herself by terminating the process, so to reiterate you must definitely ensure that progress has already been saved.

Raises:
  • UnicodeDecodeError – If data is unable to be decoded (though this is unlikely to happen).

  • orjson.JSONEncodeError – If unable to encode JSON data.

abstractmethod async handle_action(action: NeuroAction) None

Handle an Action request from Neuro.

Parameters:

action (NeuroAction) – Parsed Neuro action request data.

Warning

Should call send_action_result with this action’s id as soon as scheduling action processing is complete, or else Neuro will be stuck frozen, waiting.

async handle_graceful_shutdown_request(wants_shutdown: bool) None

Handle a graceful shutdown request from Neuro.

This is part of the game automation API, which will only be used for games that Neuro can launch by herself. As such, most games will not need to implement this.

This message will be sent when Neuro decides to stop playing a game, or upon manual intervention from the dashboard. You should create or identify graceful shutdown points where the game can be closed gracefully after saving progress. You should store the latest received wants_shutdown value, and if it is true when a graceful shutdown point is reached, you should save the game and quit to main menu, then send back a shutdown ready message.

Parameters:

wants_shutdown (bool) – Whether the game should shutdown at the next graceful shutdown point. - If True: Shutdown is requested - If False: Cancel the prior shutdown request

Warning

Please don’t actually close the game, just quit to main menu. Neuro will close the game herself.

Note

Base implementation sends that shutdown is ready.

async handle_immediate_shutdown() None

Handle immediate shutdown alert from Neuro.

This is part of the game automation API, which will only be used for games that Neuro can launch by herself. As such, most games will not need to implement this.

This message will be sent when the game needs to be shutdown immediately. You have only a handful of seconds to save as much progress as possible. After you have saved, you can send back a shutdown ready message.

Warning

Please don’t actually close the game, just save the current progress that can be saved. Neuro will close the game herself.

Note

Base implementation sends that shutdown is ready.

async read_message() None

Read message from Neuro websocket.

You should call this function in a loop as long as the websocket is still connected.

Automatically handles actions/reregister_all commands.

Calls handle_graceful_shutdown_request and handle_immediate_shutdown for graceful and immediate shutdown requests respectively.

Calls handle_action for action commands.

Calls handle_unknown_command for any other command.

Raises:
  • ValueError – If extra keys in action command data or missing keys in action command data.

  • TypeError – If action command key type mismatch

Note

Does not catch any exceptions read_raw_server_message raises.

Initialization

AbstractNeuroAPI.__init__(game_title: str) None

Initialize the Neuro API for a specific game.

Parameters:

game_title (str) – The name of the game to be integrated with the Neuro system.

Note

Initializes the internal action registry to track currently registered actions.

Initialize the Neuro API client for a specific game.

The game title should be the display name of your game, including spaces and symbols (e.g., “Buckshot Roulette”, “Among Us”).

Core Methods

These methods provide the primary functionality for game integration:

async AbstractNeuroAPI.send_startup_command() None

Send startup command to initialize the game with Neuro.

This method sends the initial message to the Neuro system when a game starts. It serves two critical purposes: - Inform Neuro that the game is now running - Clear and reset any previously registered actions

Note

This should be the very first message sent after game initialization.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the startup command.

Warning

Sends a command that clears all previously registered actions for this game, performing a complete action registry reset.

Critical: This must be the first command sent when your game starts.

async def game_startup():
    api = MyGameAPI("My Game")
    await api.send_startup_command()  # Clear previous state
    # Now register actions...
async AbstractNeuroAPI.send_context(message: str, silent: bool = True) None

Send a contextual message to Neuro about the game state.

Allows communication of game events or state information to Neuro without necessarily requiring an immediate response.

Parameters:
  • message (str) – A plaintext description of what is happening in the game. This information will be directly received by Neuro.

  • silent (bool, optional) –

    Controls Neuro’s response behaviour: - If True (default): Message is added to context silently

    without prompting a response.

    • If False: Neuro _might_ respond directly, unless she is busy talking to someone else or to chat.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the context command.

Note

This method provides a flexible way to keep Neuro informed about game events without disrupting ongoing interactions.

Communicate game events and state to Neuro.

# Silent context (no response expected)
await api.send_context("Player entered the forest area")

# Interactive context (may prompt response)
await api.send_context("Player seems confused and stuck", silent=False)
async AbstractNeuroAPI.register_actions(actions: list[Action]) None

Register a list of actions with Neuro.

Validates and registers multiple actions for Neuro to use during game interaction. This method performs two key operations: - Validates each action’s name and schema - Sends the actions to Neuro for registration

Parameters:

actions (list[command.Action]) – A list of actions to be registered. If an action is already registered, it will be ignored.

Raises:
  • ValueError – If any action: - Contains invalid characters in its name - Has an invalid schema key

  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action registration.

Note

  • Each action is validated before registration

  • Previously registered actions with the same name will not be overwritten

  • The method maintains an internal registry of registered actions

Register actions that Neuro can execute in your game.

from neuro_api.command import Action

actions = [
    Action(
        name="move_player",
        description="Move the player character",
        schema={
            "type": "object",
            "properties": {
                "direction": {"type": "string"},
                "distance": {"type": "integer", "minimum": 1}
            },
            "required": ["direction"]
        }
    ),
    Action("jump", "Make the player jump"),
    Action("attack", "Attack nearby enemies")
]

await api.register_actions(actions)
async AbstractNeuroAPI.unregister_actions(action_names: Sequence[str]) None

Unregister specified Neuro actions.

Removes actions from both the internal registry and Neuro’s action set, preventing these actions from being used in future interactions.

Parameters:

action_names (Sequence[str]) – The names of the actions to unregister. Attempting to unregister an action that isn’t registered will not cause any errors.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action unregistration.

Note

  • No error is raised for non-existent actions

Remove actions that are no longer available.

# Remove specific actions
await api.unregister_actions(["attack", "use_magic"])
async AbstractNeuroAPI.send_force_action(state: str, query: str, action_names: Sequence[str], ephemeral_context: bool = False, priority: ForcePriority = ForcePriority.LOW) None

Force Neuro to execute an action with specific context.

Sends a command to Neuro that compels her to choose and execute one of the specified actions, providing detailed game state and action instructions.

Parameters:
  • state (str) – An arbitrary string describing the current game state. Can be plaintext, JSON, Markdown, or any other format. This information will be directly received by Neuro.

  • query (str) – A plaintext message instructing Neuro on her current task (e.g., “It is now your turn. Please perform an action. If you want to use any items, you should use them before picking up the shotgun.”). This information will be directly received by Neuro.

  • action_names (Sequence[str]) – Names of actions Neuro can choose from during this force action.

  • ephemeral_context (bool, optional) –

    Controls context persistence: - If False (default): The state and query context will

    be remembered after actions force completion.

    • If True: Neuro will only remember the context during the actions force.

  • priority (command.ForcePriority) – Determines how urgently Neuro should respond to the action force when she is speaking. If Neuro is not speaking, this setting has no effect. The default is command.ForcePriority.LOW, which will cause Neuro to wait until she finishes speaking before responding. command.ForcePriority.MEDIUM causes her to finish her current utterance sooner. command.ForcePriority.HIGH prompts her to process the action force immediately, shortening her utterance and then responding. command.ForcePriority.CRITICAL will interrupt her speech and make her respond at once. Use command.ForcePriority.CRITICAL with caution, as it may lead to abrupt and potentially jarring interruptions.

Raises:
  • ValueError – If any specified action name is not currently registered.

  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action force command.

Warning

  • Neuro can only handle one action force at a time.

  • Sending an action force while another is in progress will cause problems.

Force Neuro to choose from specific actions immediately.

Warning

Only one action force can be active at a time. Multiple concurrent forces will cause problems.

await api.send_force_action(
    state="Player HP: 25/100, Enemy HP: 50/100, In combat",
    query="Choose your action for this turn in combat",
    action_names=["attack", "defend", "use_potion", "flee"],
    ephemeral_context=True  # Don't remember this context after action
)
async AbstractNeuroAPI.send_action_result(id_: str, success: bool, message: str | None = None) None

Report the result of a Neuro-initiated action.

Communicates the outcome of an action to Neuro, allowing her to proceed with her decision-making process. This method is critical for maintaining the flow of game interactions.

Parameters:
  • id (str) – The unique identifier of the action being reported. This ID is directly obtained from the original action message.

  • success (bool) –

    Indicates the action’s outcome: - If True: Action was successfully executed. - If False: Action failed. Note: If this action is part

    of an actions force, Neuro will immediately retry the entire actions force.

  • message (str, optional) –

    A descriptive message about the action’s execution: - For unsuccessful actions: Should be an error message. - For successful actions: Can be empty or provide a _small_

    context about the action (e.g., “Remember to not share this with anyone.”).

    This information will be directly received by Neuro.

Raises:
  • UnicodeDecodeError – If the command data cannot be decoded (highly unlikely).

  • orjson.JSONEncodeError – If unable to encode the JSON data for the action result.

Warning

  • Until an action result is sent, Neuro will be waiting and unable to proceed.

  • Send this method call as soon as possible after action validation, preferably before in-game execution.

Note

To prevent automatic retrying of a failed action: - Set success to True - Provide an error message in the message field

Report the outcome of an action execution.

Important

Send this immediately after validating the action, not after executing it in-game.

# Successful action
await api.send_action_result(
    action.id_,
    success=True,
    message="Successfully moved north"
)

# Failed action
await api.send_action_result(
    action.id_,
    success=False,
    message="Cannot move - path blocked by wall"
)

Utility Methods

AbstractNeuroAPI.get_registered() tuple[str, ...]

Return the names of all currently registered actions.

Returns:

A tuple containing the names of all actions currently registered in the Neuro API.

Return type:

tuple[str, …]

Note

This method provides a snapshot of registered actions at the time of calling.

Get names of currently registered actions.

registered = api.get_registered()
print(f"Available actions: {', '.join(registered)}")

Abstract Methods

These methods must be implemented in your game-specific subclass:

abstractmethod async AbstractNeuroAPI.handle_action(action: NeuroAction) None

Handle an Action request from Neuro.

Parameters:

action (NeuroAction) – Parsed Neuro action request data.

Warning

Should call send_action_result with this action’s id as soon as scheduling action processing is complete, or else Neuro will be stuck frozen, waiting.

Required implementation: Process action requests from Neuro.

This is the main method where your game logic handles Neuro’s actions.

async def handle_action(self, action: NeuroAction):
    try:
        # Parse action data if present
        data = None
        if action.data:
            data = json.loads(action.data)

        # Validate action
        if action.name not in self.get_registered():
            await self.send_action_result(
                action.id_,
                False,
                f"Unknown action: {action.name}"
            )
            return

        # Execute action based on name
        if action.name == "move_player":
            success = await self.execute_move(data["direction"])
            message = "Moved successfully" if success else "Move failed"
        elif action.name == "attack":
            success = await self.execute_attack()
            message = "Attack executed" if success else "Attack failed"
        else:
            success = False
            message = f"Unhandled action: {action.name}"

        # Always send result
        await self.send_action_result(action.id_, success, message)

    except Exception as e:
        # Handle errors gracefully
        await self.send_action_result(
            action.id_,
            False,
            f"Action failed: {str(e)}"
        )

Websocket Methods (from AbstractNeuroAPIClient)

These must be implemented to handle websocket communication:

abstractmethod async AbstractNeuroAPI.write_to_websocket(data: str) None

Abstract method to write a message to the websocket.

This method must be implemented by subclasses to define the specific mechanism for sending data over a websocket.

Parameters:

data (str) – The message to be sent over the websocket.

abstractmethod async AbstractNeuroAPI.read_from_websocket() bytes | bytearray | memoryview | str

Abstract method to read a message from the websocket.

This method must be implemented by subclasses to define the specific mechanism for receiving data from a websocket.

Returns:

The message received from the websocket, supporting anything orjson.loads can handle.

Return type:

bytes | bytearray | memoryview | str

Game Automation Methods

These methods handle automated game launching (most games won’t need these):

async AbstractNeuroAPI.send_shutdown_ready() None

Send shutdown ready response.

This is part of the game automation API, which will only be used for games that Neuro can launch by herself. As such, most games will not need to implement this.

This should be sent as a response to a graceful or an imminent shutdown request, after progress has been saved. After this is sent, Neuro will close the game herself by terminating the process, so to reiterate you must definitely ensure that progress has already been saved.

Raises:
  • UnicodeDecodeError – If data is unable to be decoded (though this is unlikely to happen).

  • orjson.JSONEncodeError – If unable to encode JSON data.

async AbstractNeuroAPI.handle_graceful_shutdown_request(wants_shutdown: bool) None

Handle a graceful shutdown request from Neuro.

This is part of the game automation API, which will only be used for games that Neuro can launch by herself. As such, most games will not need to implement this.

This message will be sent when Neuro decides to stop playing a game, or upon manual intervention from the dashboard. You should create or identify graceful shutdown points where the game can be closed gracefully after saving progress. You should store the latest received wants_shutdown value, and if it is true when a graceful shutdown point is reached, you should save the game and quit to main menu, then send back a shutdown ready message.

Parameters:

wants_shutdown (bool) – Whether the game should shutdown at the next graceful shutdown point. - If True: Shutdown is requested - If False: Cancel the prior shutdown request

Warning

Please don’t actually close the game, just quit to main menu. Neuro will close the game herself.

Note

Base implementation sends that shutdown is ready.

async AbstractNeuroAPI.handle_immediate_shutdown() None

Handle immediate shutdown alert from Neuro.

This is part of the game automation API, which will only be used for games that Neuro can launch by herself. As such, most games will not need to implement this.

This message will be sent when the game needs to be shutdown immediately. You have only a handful of seconds to save as much progress as possible. After you have saved, you can send back a shutdown ready message.

Warning

Please don’t actually close the game, just save the current progress that can be saved. Neuro will close the game herself.

Note

Base implementation sends that shutdown is ready.

Message Processing

async AbstractNeuroAPI.read_message() None

Read message from Neuro websocket.

You should call this function in a loop as long as the websocket is still connected.

Automatically handles actions/reregister_all commands.

Calls handle_graceful_shutdown_request and handle_immediate_shutdown for graceful and immediate shutdown requests respectively.

Calls handle_action for action commands.

Calls handle_unknown_command for any other command.

Raises:
  • ValueError – If extra keys in action command data or missing keys in action command data.

  • TypeError – If action command key type mismatch

Note

Does not catch any exceptions read_raw_server_message raises.

Main message processing loop. Call this continuously while connected.

The method automatically handles:

  • action commands → calls handle_action()

  • actions/reregister_all → re-registers all current actions

  • shutdown/graceful → calls handle_graceful_shutdown_request()

  • shutdown/immediate → calls handle_immediate_shutdown()

  • Unknown commands → calls handle_unknown_command()

Complete Usage Example

Here’s a complete example of implementing a Neuro API client:

import asyncio
import json
import websockets
from neuro_api.api import AbstractNeuroAPI, NeuroAction
from neuro_api.command import Action

class MyGameAPI(AbstractNeuroAPI):
    def __init__(self, websocket):
        super().__init__("My Awesome Game")
        self.websocket = websocket
        self.player_position = {"x": 0, "y": 0}
        self.player_health = 100

    # Required websocket methods
    async def write_to_websocket(self, data: str) -> None:
        await self.websocket.send(data)

    async def read_from_websocket(self) -> str:
        return await self.websocket.recv()

    # Required action handler
    async def handle_action(self, action: NeuroAction) -> None:
        try:
            success = False
            message = ""

            if action.name == "move":
                data = json.loads(action.data) if action.data else {}
                direction = data.get("direction", "north")
                success = await self.move_player(direction)
                message = f"Moved {direction}" if success else "Move blocked"

            elif action.name == "heal":
                success = await self.heal_player()
                message = "Healed successfully" if success else "No healing items"

            elif action.name == "status":
                success = True
                message = f"Health: {self.player_health}, Position: {self.player_position}"

            else:
                message = f"Unknown action: {action.name}"

            await self.send_action_result(action.id_, success, message)

        except Exception as e:
            await self.send_action_result(
                action.id_,
                False,
                f"Error executing action: {str(e)}"
            )

    # Game logic methods
    async def move_player(self, direction: str) -> bool:
        moves = {
            "north": (0, 1), "south": (0, -1),
            "east": (1, 0), "west": (-1, 0)
        }

        if direction in moves:
            dx, dy = moves[direction]
            self.player_position["x"] += dx
            self.player_position["y"] += dy

            # Send context about the move
            await self.send_context(
                f"Player moved {direction} to {self.player_position}"
            )
            return True
        return False

    async def heal_player(self) -> bool:
        if self.player_health < 100:
            self.player_health = min(100, self.player_health + 25)
            return True
        return False

    async def initialize_game(self):
        # Send startup command
        await self.send_startup_command()

        # Register available actions
        actions = [
            Action(
                name="move",
                description="Move the player in a direction",
                schema={
                    "type": "object",
                    "properties": {
                        "direction": {
                            "type": "string",
                            "enum": ["north", "south", "east", "west"]
                        }
                    },
                    "required": ["direction"]
                }
            ),
            Action("heal", "Heal the player character"),
            Action("status", "Check player status")
        ]

        await self.register_actions(actions)

        # Send initial context
        await self.send_context("Game initialized, player ready for action")

async def main():
    uri = "ws://localhost:8765"
    async with websockets.connect(uri) as websocket:
        api = MyGameAPI(websocket)
        await api.initialize_game()

        # Main game loop
        try:
            while True:
                await api.read_message()
        except websockets.exceptions.ConnectionClosed:
            print("Connection to Neuro closed")

if __name__ == "__main__":
    asyncio.run(main())

Best Practices

Initialization Sequence

Always follow this order when starting your game:

# 1. Send startup command (clears previous state)
await api.send_startup_command()

# 2. Register your actions
await api.register_actions(actions)

# 3. Send initial context
await api.send_context("Game ready")
Action Result Timing

Send action results immediately after validation, not after game execution:

async def handle_action(self, action: NeuroAction):
    # Validate first
    if not self.is_valid_action(action):
        await self.send_action_result(action.id_, False, "Invalid action")
        return

    # Send success result immediately
    await self.send_action_result(action.id_, True, "Action validated")

    # Then execute in game (this can be slow)
    await self.execute_action_in_game(action)
Error Handling

Always handle errors gracefully and send appropriate results:

async def handle_action(self, action: NeuroAction):
    try:
        # Action logic here
        await self.send_action_result(action.id_, True, "Success")
    except ValidationError as e:
        await self.send_action_result(action.id_, False, f"Validation failed: {e}")
    except Exception as e:
        await self.send_action_result(action.id_, False, f"Unexpected error: {e}")
Context Updates

Use context messages to keep Neuro informed about important game events:

# Good context examples
await api.send_context("Player entered boss room")
await api.send_context("Enemy defeated, gained 100 XP")
await api.send_context("Low health warning: 15/100 HP")
Action Design

Design actions that are atomic and clear:

# Good - specific actions
Action("move_north", "Move player one step north")
Action("attack_sword", "Attack with equipped sword")
Action("use_health_potion", "Use a health potion from inventory")

# Avoid - overly generic actions
Action("do_something", "Do something in the game")
Action("action", "Perform an action")

Error Handling

The API module handles various error conditions:

Action Validation Errors

When registering actions with invalid names or schemas:

try:
    await api.register_actions(actions)
except ValueError as e:
    print(f"Action registration failed: {e}")
Command Processing Errors

When receiving malformed action commands:

# The read_message() method handles these automatically
# and logs appropriate error messages
Websocket Errors

Connection issues should be handled in your main loop:

try:
    while True:
        await api.read_message()
except websockets.exceptions.ConnectionClosed:
    print("Lost connection to Neuro")
except Exception as e:
    print(f"Unexpected error: {e}")

Dependencies

This module builds upon:

  • neuro_api.client: Abstract websocket client interface

  • neuro_api.command: Command formatting and validation

  • neuro_api._deprecate: Deprecation utilities

License

This module is licensed under the GNU Lesser General Public License Version 3.

Note

Copyright (C) 2025 CoolCat467. This program is free software and comes with ABSOLUTELY NO WARRANTY.