Extensions - Capsize-Games/airunner GitHub Wiki

AI Runner Plugin System

AI Runner supports custom plugins that extend functionality through widgets, background services, or signal-based behavior.

To install a plugin, place it in the extensions directory located in the AI Runner base path. You can find the base path location in the Settings documentation.

β”œβ”€β”€ [AI Runner Base Path]/extensions
    └── extension_folder

Writing a Custom Plugin

Each plugin must define a Plugin class that inherits from BasePlugin, and optionally, a custom widget class that inherits from BaseWidget.

Here's a basic example of a plugin that adds a simple logging widget:

from PySide6.QtWidgets import QWidget, QTextEdit, QVBoxLayout, QPushButton
from airunner.widgets.base_widget import BaseWidget
from airunner.base_plugin import BasePlugin
from airunner.enums import SignalCode


class LoggerWidget(BaseWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.layout = QVBoxLayout(self)
        self.text_area = QTextEdit()
        self.log_button = QPushButton("Log Message")

        self.layout.addWidget(self.text_area)
        self.layout.addWidget(self.log_button)

        self.log_button.clicked.connect(self.log_message)

    def log_message(self):
        message = self.text_area.toPlainText()
        if message:
            print(f"[LoggerPlugin] {message}")
            self.emit_signal(SignalCode.LOG_EVENT, {"message": message})


class Plugin(BasePlugin):
    name = "Logger"
    version = "1.0.0"
    airunner_version = ">=3.3.0"

    def get_widget(self) -> QWidget:
        return LoggerWidget()

Notes

The Plugin class must define:

  • name: The plugin's display name.
  • version: Your plugin's version.
  • airunner_version: The minimum compatible version of AI Runner.
  • get_widget(): Optional. Returns a QWidget to display in the interface.

You can use emit_signal(SignalCode.YOUR_SIGNAL, data) from BaseWidget to communicate with other parts of the application.

Place any assets, UI files, or helpers in the same plugin folder as needed.


Advanced Plugin Features

Plugin Directory Structure

Each plugin must reside in the extensions directory within the AI Runner base path. Example structure:

[AI Runner Base Path]/extensions
    β”œβ”€β”€ my_plugin
    β”‚   β”œβ”€β”€ __init__.py
    β”‚   β”œβ”€β”€ plugin.py
    β”‚   β”œβ”€β”€ assets/
    β”‚   └── helpers.py

Plugin Configuration

  • name: Display name of the plugin.
  • version: Plugin version.
  • airunner_version: Minimum compatible version of AI Runner.
  • get_widget(): Optional method to return a QWidget for the interface.

Signal Communication

Plugins can emit signals to communicate with other parts of the application. Example:

self.emit_signal(SignalCode.LOG_EVENT, {"message": "Plugin initialized"})

Debugging Plugins

  • Use the --debug flag when running AI Runner to enable verbose logging for plugins.
  • Check logs in the logs/ directory for detailed error messages.

Example Plugin

Here’s a basic example of a plugin that logs messages:

from PySide6.QtWidgets import QWidget, QTextEdit, QVBoxLayout, QPushButton
from airunner.widgets.base_widget import BaseWidget
from airunner.base_plugin import BasePlugin
from airunner.enums import SignalCode

class LoggerWidget(BaseWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.layout = QVBoxLayout(self)
        self.text_area = QTextEdit()
        self.log_button = QPushButton("Log Message")
        self.layout.addWidget(self.text_area)
        self.layout.addWidget(self.log_button)
        self.log_button.clicked.connect(self.log_message)

    def log_message(self):
        message = self.text_area.toPlainText()
        if message:
            print(f"[LoggerPlugin] {message}")
            self.emit_signal(SignalCode.LOG_EVENT, {"message": message})

class Plugin(BasePlugin):
    name = "Logger"
    version = "1.0.0"
    airunner_version = ">=3.3.0"

    def get_widget(self) -> QWidget:
        return LoggerWidget()