简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

name: erispulse-ecosystem description: "适用于:了解生态组件(Dashboard/Cron/AI 模块等)与各平台适配器的接入差异。覆盖场景:Сама платформа ErisPulse предоставляет только основные возможности (система событий, система модулей, конфигурация, маршрутизация, логирование и т.д.), не включая в себя такие "тяжелые" функции, как GUI, рендеринг изображений, визуализация и т.д. Эти возможности предоставляются третьими сторонами и поддерживаются сообществом, и устанавливаются по мере необходимости.。Когда это нужно читать: Когда вы хотите использовать веб-интерфейс для визуального управления роботом (включение/выключение модулей, редактирование конфигурации, просмотр логов, мониторинг потоков событий), или хотите зарегистрировать страницу управления для своего модуля. Если не нужно — пропустите.。Когда стоит читать этот документ: когда вашему модулю требуется логика запуска по расписанию или с задержкой (напоминания по расписанию, периодический мониторинг, планирование по Cron-выражениям), и вы хотите, чтобы задачи не терялись после перезапуска фреймворка. Если это не ваш сл..."

ErisPulse 生态与多平台

This skill is auto-built from the ErisPulse documentation. Repository: https://github.com/ErisPulse/ErisPulse Source paths are annotated per section; see docs/ in the repository for the latest content.

内容大纲

AI 按需读取:只读需要的章节即可,不必全文加载。

生态总览

来源: docs/ru/ecosystem/README.md(https://github.com/ErisPulse/ErisPulse/blob/main/docs/ru/ecosystem/README.md)

Экологические модули

Сама платформа ErisPulse предоставляет только основные возможности (система событий, система модулей, конфигурация, маршрутизация, логирование и т.д.), не включая в себя такие "тяжелые" функции, как GUI, рендеринг изображений, визуализация и т.д. Эти возможности предоставляются третьими сторонами и поддерживаются сообществом, и устанавливаются по мере необходимости.

Important

Документация в этом разделе делится на два типа, способ установки которых различается:

  • Модули (например, Dashboard / Takumi) устанавливаются с помощью epsdk install:

    epsdk install <имя_модуля>
    
  • Отдельные программы (например, клиент ErisPulse-App) устанавливаются напрямую из GitHub Releases, без использования epsdk.


Рекомендуемые модули

ErisPulse-Dashboard: Панель управления в браузере

Запускаете бота на сервере, но управляете модулями, настройками и логами через терминал? Dashboard переносит эти функции в браузер: управление модулями, редактирование конфигураций, просмотр логов, мониторинг событий; другие модули могут регистрировать собственные окна в боковой панели, и все управление сосредоточено в одном месте.

epsdk install Dashboard

Документация: Использование Dashboard и регистрация окон | Главная страница проекта: PyPI

ErisPulse-Cron: Планировщик задач

Нужно ежедневно отправлять напоминания о регистрации, выполнять задачи по расписанию с помощью Cron-выражений, или периодически запрашивать данные каждые несколько минут? Cron предоставляет три типа задач: одноразовые, интервальные и по Cron-выражениям, с передачей параметров в обратный вызов, а также SQLite-хранилище (задачи не теряются при перезапуске).

epsdk install Cron

Документация: Планировщик задач Cron | Главная страница проекта: GitHub

ErisPulse-QvQChat: Общий агент

Хотите, чтобы в группе был AI-ассистент, который может выполнять полезные задачи, а не просто отвечать по ключевым словам? QvQChat — это универсальный агент: циклически обрабатывает отправку и получение сообщений, выполнение кода, управление компьютером, генерацию изображений, голосовые сообщения, MCP и подагентов, поддерживает потоковой диалог и последовательное выполнение инструментов, включает в себя окно Dashboard.

epsdk install ErisPulse-QvQChat

Документация: Агент QvQChat | Главная страница проекта: GitHub

ErisPulse-Takumi: Генерация изображений

Для сцен, где требуется "отправлять изображения", например, рейтинги, отчеты о боях или карточки расписания, достаточно написать шаблон и отрендерить изображение для отправки в группу: поддержка HTML / деревьев узлов / Jinja / SVG / анимации (на основе takumi-py), включает шрифты на китайском и английском языках, готов к использованию без дополнительной настройки.

epsdk install Takumi

Документация: Генерация изображений Takumi | Главная страница проекта: GitHub (автор @ccd2s)

Официальный клиент (независимое приложение)

ErisPulse-App: запуск бота прямо на телефоне

Нет постоянного сервера, но вы хотите создавать экземпляры, устанавливать модули и просматривать поток событий в любое время? ErisPulse-App — это официальный клиент для всех платформ (Android / Windows / Linux / macOS): создание / запуск / управление несколькими экземплярами ботов с помощью родного интерфейса, встроенный магазин модулей и конструктор событий, запуск прямо с телефона, постоянное присутствие в системном трее на рабочем столе.

Скачайте установочные пакеты для всех платформ с GitHub Releases, для этого не требуется epsdk.

Документация: Установка и использование ErisPulse-App

Я тоже хочу добавить свой модуль сюда?

Добро пожаловать, чтобы рекомендовать качественные, повторно используемые модули экосистемы ErisPulse. Требования:

  1. Опубликован на PyPI, и имя пакета начинается с ErisPulse-
  2. Предоставляет базовый README и примеры использования
  3. Активно поддерживается, с ответами на Issue

Авторы модулей, соответствующих вышеуказанным условиям, могут добавить документ <имя_модуля>.md в этом каталоге через PR и дополнить соответствующий раздел в рекомендованном списке вверху.

Dashboard

来源: docs/ru/ecosystem/dashboard.md(https://github.com/ErisPulse/ErisPulse/blob/main/docs/ru/ecosystem/dashboard.md)

ErisPulse-Dashboard

Tip

Когда это нужно читать: Когда вы хотите использовать веб-интерфейс для визуального управления роботом (включение/выключение модулей, редактирование конфигурации, просмотр логов, мониторинг потоков событий), или хотите зарегистрировать страницу управления для своего модуля. Если не нужно — пропустите.

ErisPulse-Dashboard — это веб-панель управления, поддерживаемая ErisDev, которая предоставляет визуальный интерфейс для управления ErisPulse в режиме выполнения: включение/выключение модулей, редактирование конфигурации, просмотр логов, мониторинг потоков событий и т.д.

Important

Dashboard не является встроенной функцией фреймворка ErisPulse, его нужно устанавливать отдельно:

epsdk install Dashboard

Dashboard также поддерживает регистрацию пользовательских страниц управления другими модулями ErisPulse в боковой панели. После регистрации пользователь может напрямую переключиться на специальную визуальную страницу модуля в Dashboard, без необходимости дополнительного разработки отдельного пользовательского интерфейса.

Note

Регистрация визуальных окон — это необязательная функция.

  • Если модуль Dashboard не установлен или не загружен, вызов sdk.Dashboard.register_view() вызовет исключение
  • Обязательно используйте try/except для обертывания кода регистрации, чтобы убедиться, что другие функции модуля не будут затронуты
  • Рекомендуется проверять доступность Dashboard перед регистрацией: hasattr(sdk, 'Dashboard') and sdk.Dashboard

Принцип работы

Модуль on_load()
  → вызов sdk.Dashboard.register_view(...)
  → Dashboard сохраняет информацию о визуальном окне
  → WebSocket уведомляет клиент
  → Клиент динамически создает элемент навигации в боковой панели + контейнер страницы
  → Пользователь может переключиться на страницу модуля

API регистрации

sdk.Dashboard.register_view(
    id="MyModule",                    # Обязательный, уникальный идентификатор
    title="Мой модуль",                  # Название на китайском
    title_en="My Module",             # Название на английском
    icon_svg='<svg>...</svg>',        # SVG-иконка для боковой панели
    html_content='<div>...</div>',     # HTML-контент страницы
    js_content='function xxx() {}',    # JavaScript-логика страницы
    css_content='.my-style {}',        # Необязательный пользовательский CSS
    iframe_url='',                     # URL для режима iframe (один из двух: html_content или iframe_url)
    loader="loadMyModuleView",         # Имя функции JavaScript, вызываемой при переключении на страницу
    group="group_extensions",          # Группа в боковой панели
    group_title="",                    # Название группы на китайском
    group_title_en="",                 # Название группы на английском
)

Описание параметров

Параметр Тип Обязательно Описание
id str Да Уникальный идентификатор визуального окна, рекомендуется использовать название модуля
title str Нет Название для отображения на китайском, по умолчанию используется id
title_en str Нет Название для отображения на английском, по умолчанию используется title
icon_svg str Нет Полная строка SVG-иконки для боковой панели
html_content str Нет* HTML-контент страницы в режиме встраивания
js_content str Нет JavaScript-код страницы
css_content str Нет Пользовательский CSS-стиль страницы
iframe_url str Нет* URL для режима iframe, при указании игнорируется html_content
loader str Нет Имя функции JavaScript, вызываемой при активации страницы
group str Нет Идентификатор группы в боковой панели, по умолчанию group_extensions
group_title str Нет Название группы на китайском
group_title_en str Нет Название группы на английском

*Обязательно указывать либо html_content, либо iframe_url, иначе страница будет пустой.


Два режима встраивания

Режим 1: HTML/JS встраивание (рекомендуется)

Предоставляйте HTML, JS и CSS напрямую, Dashboard вставит содержимое на страницу. Этот режим полностью соответствует стилям Dashboard, рекомендуется использовать CSS-классы, предоставляемые Dashboard.

sdk.Dashboard.register_view(
    id="HelloPage",
    title="Привет страница", title_en="Hello",
    icon_svg='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/></svg>',
    html_content='<h1 class="page-title">Hello World</h1><div class="card"><div class="card-body">Это пример страницы</div></div>',
    group="group_tools",
)

Полный пример модуля погоды (с API-маршрутами, JS-взаимодействием и т.д.) см. ниже Полный пример модуля.

Режим 2: Встраивание с помощью iframe

Модуль предоставляет URL своей HTML-страницы (необходимо зарегистрировать маршрут), Dashboard встраивает её в iframe. Подходит для сценариев с полностью независимым UI или сложным взаимодействием.

sdk.Dashboard.register_view(
    id="MyVisualizer",
    title="Визуализация данных", title_en="Data Visualizer",
    iframe_url="/MyVisualizer/view",
    group="group_tools",
)

В режиме iframe автоматически добавляется параметр token в URL для аутентификации.


Группировка в боковой панели

Модуль может указать группу, в которой будет отображаться визуальное окно. Dashboard предоставляет следующие встроенные группы:

Идентификатор группы Название на китайском Позиция
group_overview Обзор 1-я группа
group_events События 2-я группа
group_extensions Расширения 3-я группа (по умолчанию)
group_system Система 4-я группа
group_tools Инструменты 5-я группа

Указав идентификатор встроенной группы, визуальное окно будет добавлено в конец этой группы:

group="group_tools"  # Добавление в группу "Инструменты"

Также можно использовать пользовательские идентификаторы групп (не начинающиеся с group_), Dashboard автоматически создаст новую группу:

group="my_group",
group_title="Моя группа",
group_title_en="My Group",

Распространённые CSS-классы

При использовании режима встраивания HTML, можно напрямую использовать CSS-классы, предоставленные Dashboard, для обеспечения визуальной согласованности:

Класс Назначение
page-title Заголовок страницы, например <h1 class="page-title">Заголовок</h1>
card Контейнер карточки
card-header Заголовок карточки
card-body Тело карточки
grid-2 Двухколоночный макет сетки
grid-3 Трёхколоночный макет сетки
btn Базовая кнопка
btn-primary Основная кнопка (синяя)
btn-secondary Второстепенная кнопка
btn-icon Кнопка с иконкой
btn-danger Кнопка опасного действия

Dashboard использует CSS-переменные для управления темой, которые можно использовать в модуле:

CSS-переменная Назначение
var(--bg-p) Основной фон
var(--bg-s) Вторичный фон
var(--bg-t) Третичный фон (карточки и т.д.)
var(--tx-p) Основной цвет текста
var(--tx-s) Вторичный цвет текста
var(--tx-t) Вспомогательный цвет текста
var(--bd) Цвет границы
var(--accent) Акцентный цвет
var(--ok-c) Цвет успеха
var(--er-c) Цвет ошибки

Эти переменные автоматически переключаются между светлой и тёмной темами Dashboard, модулю не нужно дополнительно обрабатывать.


Аутентификация и вызов API

При вызове API модуля из JavaScript визуального окна необходимо передавать токен Dashboard для аутентификации:

var token = localStorage.getItem('__ep_tk__');
var resp = await fetch('/YourModule/api/data', {
    headers: { 'Authorization': 'Bearer ' + token }
});
var data = await resp.json();

API-точки модуля могут самостоятельно решать, нужно ли проверять токен. Если нужно проверить, можно извлечь его из заголовка:

async def _api_data(self, request):
    token = request.headers.get("Authorization", "").replace("Bearer ", "")
    if not token:
        return {"error": "Unauthorized"}, 401
    return {"data": "hello"}

Полный пример модуля

Ниже приведён полный пример модуля погоды, демонстрирующий регистрацию визуального окна, предоставление данных API и очистку ресурсов при выгрузке:

from ErisPulse import sdk
from ErisPulse.Core.Bases import BaseModule
from ErisPulse.Core.Event import command


class Main(BaseModule):
    def __init__(self):
        self.sdk = sdk
        self.logger = sdk.logger.get_child("Weather")
        self.config = self._load_config()

    @staticmethod
    def get_load_strategy():
        from ErisPulse.loaders import ModuleLoadStrategy
        return ModuleLoadStrategy(lazy_load=False, priority=50)

    async def on_load(self, event):
        self._register_routes()
        self._register_dashboard_view()
        self.logger.info("Модуль погоды загружен")

    async def on_unload(self, event):
        self._unregister_routes()
        if hasattr(self.sdk, 'Dashboard') and self.sdk.Dashboard:
            self.sdk.Dashboard.unregister_view("Weather")
        self.logger.info("Модуль погоды выгружен")

    def _load_config(self):
        config = self.sdk.config.getConfig("Weather")
        if not config:
            default = {"city": "Пекин", "api_key": ""}
            self.sdk.config.setConfig("Weather", default)
            return default
        return config

    def _register_routes(self):
        r = self.sdk.router
        r.register_http_route("Weather", "/api/current",
                              handler=self._api_current, methods=["GET"])

    def _unregister_routes(self):
        r = self.sdk.router
        try:
            r.unregister_http_route("Weather", "/api/current")
        except Exception:
            pass

    async def _api_current(self, request):
        return {
            "city": self.config.get("city", "Пекин"),
            "temp": 25,
            "humidity": 60,
        }

    def _register_dashboard_view(self):
        try:
            dashboard = self.sdk.Dashboard
            dashboard.register_view(
                id="Weather",
                title="Погода", title_en="Weather",
                icon_svg='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>',
                html_content='''
                    <h1 class="page-title">Погодный запрос</h1>
                    <p style="color:var(--tx-s);margin-bottom:16px">Просмотр текущей погоды</p>
                    <div class="grid-2">
                        <div class="card">
                            <div class="card-header">Текущая погода</div>
                            <div class="card-body">
                                <div id="weather-info" style="font-size:14px;color:var(--tx-s)">Нажмите, чтобы обновить</div>
                            </div>
                        </div>
                        <div class="card">
                            <div class="card-header">Действия</div>
                            <div class="card-body">
                                <button class="btn btn-primary" onclick="refreshWeather()">Обновить</button>
                            </div>
                        </div>
                    </div>
                ''',
                js_content='''
                    async function loadWeatherView() { await refreshWeather(); }
                    async function refreshWeather() {
                        var el = document.getElementById('weather-info');
                        if (!el) return;
                        el.textContent = 'Загрузка...';
                        try {
                            var resp = await fetch('/Weather/api/current', {
                                headers: { 'Authorization': 'Bearer ' + localStorage.getItem('__ep_tk__') }
                            });
                            var data = await resp.json();
                            el.innerHTML = '<p>Город: ' + (data.city || '--') + '</p>' +
                                           '<p>Температура: ' + (data.temp || '--') + '°C</p>' +
                                           '<p>Влажность: ' + (data.humidity || '--') + '%</p>';
                        } catch (e) {
                            el.textContent = 'Загрузка не удалась: ' + e.message;
                        }
                    }
                ''',
                loader="loadWeatherView",
                group="group_tools",
            )
        except Exception as e:
            self.logger.warning(f"Регистрация визуального окна Dashboard не удалась: {e}")

Удаление визуального окна

При выгрузке модуля следует вызвать unregister_view() для удаления зарегистрированного визуального окна:

async def on_unload(self, event):
    if hasattr(self.sdk, 'Dashboard') and self.sdk.Dashboard:
        self.sdk.Dashboard.unregister_view("Weather")

После удаления Dashboard будет удалять элементы навигации и контент в реальном времени через WebSocket, без необходимости обновления страницы.


Примечания

  1. Порядок загрузки — Dashboard загружается с приоритетом 99999 (очень высокий приоритет), приоритет вашего модуля должен быть ниже, например 50, чтобы убедиться, что Dashboard загружен первым
  2. Защитное программирование — оберните код регистрации визуального окна в try/except, потому что модуль Dashboard может не быть установлен или загружен
  3. Очистка ресурсов — в on_unload вызовите unregister_view(), чтобы удалить зарегистрированное визуальное окно
  4. Уникальность ID — параметр id должен быть уникальным во всём Dashboard, рекомендуется использовать имя модуля
  5. SVG-иконки — icon_svg должен быть полной строкой <svg>, рекомендуется использовать viewBox="0 0 24 24", и использовать stroke="currentColor" для наследования темы Dashboard
  6. Имена функций JS — имена функций в js_content должны быть уникальными (например, loadWeatherView), чтобы избежать конфликтов с другими модулями
  7. Динамическое обновление — после регистрации/удаления визуального окна Dashboard будет обновлять боковую панель в реальном времени через WebSocket, без необходимости обновления страницы

Дальнейшие шаги

定时任务

来源: docs/ru/ecosystem/cron.md(https://github.com/ErisPulse/ErisPulse/blob/main/docs/ru/ecosystem/cron.md)

ErisPulse-Cron

Tip

Когда стоит читать этот документ: когда вашему модулю требуется логика запуска по расписанию или с задержкой (напоминания по расписанию, периодический мониторинг, планирование по Cron-выражениям), и вы хотите, чтобы задачи не терялись после перезапуска фреймворка. Если это не ваш случай — пропустите.

ErisPulse-Cron — это модуль планирования задач по расписанию в экосистеме ErisPulse, предоставляющий другим модулям единый API для работы с отложенными задачами: поддерживает три типа задач — однократный запуск по времени, циклический запуск с интервалом и Cron-выражения, передачу параметров в колбэки, а также персистентность в SQLite (задачи не теряются после перезапуска).

Important

Cron не является встроенной функциональностью фреймворка ErisPulse и требует отдельной установки:

epsdk install Cron

После установки весь API доступен через sdk.Cron.


Краткий обзор возможностей


Быстрый старт

from ErisPulse import sdk

# 1. Регистрация обработчика колбэка
@sdk.Cron.on_trigger
async def handle_trigger(info):
    data = info["callback_data"]
    print(f"Задача сработала: {info['task_id']}, данные: {data}")

# 2. Создание задачи по расписанию
task_id = sdk.Cron.once(
    delay=60,
    callback_data={"type": "reminder", "msg": "Пора попить воды"},
)

Обзор API

Создание задач

# Однократная задача: срабатывает с задержкой 600 секунд
sdk.Cron.once(delay=600, callback_data={"order_id": "123"}, label="Напоминание о таймауте заказа")

# Циклическая задача: срабатывает каждые 300 секунд, максимум 100 раз
sdk.Cron.interval(interval_seconds=300, callback_data={"monitor": "server-1"}, max_runs=100)

# Cron-выражение: по будням каждый день в 9:30
sdk.Cron.cron(expression="30 9 * * 1-5", callback_data={"type": "daily_report"})

# Общие необязательные параметры: trigger_at (абсолютная временная метка), delay (задержка первого запуска), timezone,
# max_runs (0=бесконечно), label, source (имя модуля-создателя), missed_policy (политика пропущенных запусков)

Распространённые Cron-выражения: */5 * * * * (каждые 5 минут), 0 8 * * * (каждый день в 8 утра), 30 9 * * 1-5 (по будням в 9:30), 0 0 1 * * (1-го числа каждого месяца).

Колбэки

@sdk.Cron.on_trigger
async def my_handler(info):
    # info содержит task_id / task_type / callback_data / label / source /
    # run_count / max_runs / created_at / last_run / trigger_time
    ...

Поддерживается регистрация нескольких обработчиков (handler); все они вызываются по очереди, и исключение в одном из них не влияет на работу остальных.

Управление задачами

sdk.Cron.cancel(task_id)                  # Отмена
sdk.Cron.pause(task_id)                   # Пауза
sdk.Cron.resume(task_id)                  # Возобновление (reschedule=True пересчитывает время следующего запуска)
await sdk.Cron.trigger_now(task_id)       # Ручной немедленный запуск (не влияет на исходное расписание)
sdk.Cron.get_task(task_id)                # Просмотр отдельной задачи
sdk.Cron.list_tasks(source="MyModule")    # Список задач (поддерживается фильтрация по source/status/task_type)
sdk.Cron.delete_task(task_id)             # Удаление записи задачи
sdk.Cron.cleanup()                        # Очистка выполненных/отменённых задач старше 7 дней

Политика пропущенных запусков (missed_policy)

После перезапуска фреймворка для задач, у которых было пропущено время срабатывания:

Политика Поведение
fire_immediately Немедленный запуск (по умолчанию)
skip Пропустить текущий запуск и ждать следующего
reschedule Пересчитать время следующего запуска от текущего момента

Поведение при выгрузке модуля

Данные задач Cron являются персистентным активом: выгрузка или отключение модуля-создателя задачи не приводит к удалению уже созданных задач. Однако зарегистрированные этим модулем обработчики колбэков будут очищены — благодаря хукам внешней очистки на основе системы владения, Cron при хранении колбэков от имени других модулей автоматически фиксирует их владельца, и при выгрузке/отключении модуля-владельца его обработчики колбэков автоматически отбрасываются, что гарантирует корректную утилизацию экземпляров этого модуля.


Полезные ссылки


Следующие шаги

AI 对话模块

来源: docs/ru/ecosystem/qvqchat.md(https://github.com/ErisPulse/ErisPulse/blob/main/docs/ru/ecosystem/qvqchat.md)

ErisPulse-QvQChat — Универсальный агент

Tip

Когда читать этот документ: если вы хотите добавить боту возможности ИИ-агента (цикл инструментов, потоковый диалог, MCP, долговременная память) или предоставить сервисы собственного модуля для вызова агентом. Если это не требуется — пропустите.

ErisPulse-QvQChat — это универсальный модуль агента, построенный вокруг цикла инструментов: отправка и получение сообщений, вызов сервисов экосистемных модулей, написание и запуск кода, управление компьютером, генерация изображений и речи, управление задачами по расписанию и долговременной памятью — всё это осуществляется через единый протокол инструментов.

Important

QvQChat требуется установить отдельно:

epsdk install ErisPulse-QvQChat

Кроме того, необходимо добавить в «Пул моделей» как минимум одну модель, совместимую с OpenAI (Base URL, API Key, название модели).

Основные возможности

Возможность Описание
Цикл инструментов Модель генерирует вызов инструмента → параллельное выполнение → результат возвращается → продолжение вывода, пока не будет получен окончательный ответ
Потоковая беседа SSE выводит по одному символу, шаги инструментов видны в реальном времени; при обновлении / переходе и возвращении прогресс не теряется
Сжатие контекста При превышении порога токенов старый диалог автоматически сжимается в резюме (по умолчанию 128000 оценочных токенов, можно изменить)
Мост экосистемных сервисов Автоматически обнаруживает объявленные модулем сервисы и преобразует их в инструменты, добавление/удаление модуля увеличивает/уменьшает возможности
Клиент MCP stdio и Streamable HTTP, инструменты MCP объединяются в один набор инструментов
Подагенты spawn_agent запускает независимый сеанс подагент для исследования задачи, возвращает только вывод
Выполнение в процессе run_python_sdk выполняет Python в основном процессе, напрямую обращаясь к объектам среды выполнения
Управление компьютером Трехуровневый безопасный песочник (strict / standard / permissive), подтверждение опасных операций, полный аудит
Визуальное восприятие Изображения автоматически вставляются в модель (при отсутствии поддержки изображений автоматически удаляются и повторяется попытка)
Вложения Любые файлы по hash-значению сохраняются на диск, путь передается ИИ для самостоятельного обработки; вставка скриншотов через Ctrl+V
Общий доступ к сеансу Временная ссылка только для чтения (срок действия + бюджет токенов), экспорт в Markdown
Планировщик задач cron / одноразовые / периодические, сохраняются, права доступа привязаны к создателю
Перехват сеанса Администратор может предоставить агенту полный доступ к сеансу
Система личности Системный промт + начальный диалог + белый список инструментов, может быть привязан к сеансу
Долгосрочная память Каждый сеанс имеет записи памяти, которые вставляются по поиску по схожести
Автоматическое наименование ИИ После первого ответа сеанса автоматически генерируется краткое название

Модульное расширение

Любой модуль ErisPulse, объявляющий services, автоматически становится инструментом QvQChat без необходимости специального интерфейса:

from ErisPulse.Core.Bases import BaseModule, ModuleMeta

class Main(BaseModule):
    @staticmethod
    def get_meta() -> ModuleMeta:
        return ModuleMeta(name="Draw", services=[
            {"name": "draw", "description": "Генерирует изображение по описанию и возвращает URL изображения"},
        ])

    async def draw(self, prompt: str, size: str = "1024x1024"):
        return {"image_url": "https://..."}

Подпись метода автоматически сопоставляется с определением параметров JSON Schema инструмента, а первая строка docstring используется как описание параметра.

Глубокая интеграция (необязательно)

Модуль может дополнительно реализовать любую из следующих служб, каждая из которых необязательна — один модуль может быть предназначен только для расширения персонажа, а может только внедрять системные подсказки:

qvq_prompts() → Внедрение системных подсказок

Возвращает list[str] или list[{"text": str, "priority": int}], объединяя подсказки по возрастанию priority.

async def qvq_prompts(self):
    return [
        {"text": "Отправьте пользователю изображение с помощью send_message после рисования.", "priority": 10},
        {"text": "Поддерживаемые стили: аниме, реализм, акварель, пиксель.", "priority": 20},
    ]

qvq_personas() → Регистрация предустановленных персонажей

Возвращает список персонажей, id автоматически добавляется префикс ext.<имя_модуля>., модуль при отключении автоматически очищается. Подходит для модулей, специально предоставляющих расширение персонажей (например, эмоциональное сопровождение, переводчик, рецензент кода и т.д.).

async def qvq_personas(self):
    return [
        {"id": "companion", "name": "Теплый парень", "system": "Ты — тёплый и внимательный собеседник..."},
        {"id": "coder", "name": "Код-наставник", "system": "...", "tools": ["read_file", "run_python"]},
    ]

Параметр tools необязательно может ограничивать набор доступных инструментов для этого персонажа.

qvq_schemas() → Явное определение схемы параметров

Возвращает dict[имя_службы, JSON Schema], перезаписывая вывод из сигнатуры метода. Используется, когда параметры сложные или требуется строгая проверка.

async def qvq_schemas(self):
    return {
        "draw": {
            "type": "object",
            "properties": {
                "prompt": {"type": "string", "description": "Описание изображения"},
                "size": {"type": "string", "enum": ["512x512", "1024x1024"]},
            },
            "required": ["prompt"],
        },
    }

Время обновления

Время обновления глубоких интеграционных служб: запуск, установка и удаление модуля, ручное обновление на странице Dashboard «Инструменты».

Подписка на события

QvQChat транслирует два события жизненного цикла:

Событие Время Параметры
qvq.message Получено сообщение от пользователя chat_key platform sender_id sender_name text is_group
qvq.replied Отправлен ответ chat_key reply tools
async def setup(self):
    sdk.lifecycle.on("qvq.message", self.on_message)

Вызов как сервис

Сервис Подпись Описание
chat (session_id, prompt, persona="") Диалог с агентом, возвращает текст
run_prompt (chat_key, prompt, ...) Выполнение подсказки, результат может быть отправлен в целевой сеанс
get_status () Сводка о состоянии выполнения

Интерфейс

Доступ осуществляется автономно через /QvQChat/view, либо в виде встраивания в боковую панель Dashboard.

Обзор

Диалог


Следующие шаги

平台指南索引

来源: docs/ru/platform-guide/README.md(https://github.com/ErisPulse/ErisPulse/blob/main/docs/ru/platform-guide/README.md)

Документация по функциям платформы ErisPulse

Базовый протокол: OneBot12

В этом документе содержится руководство по платформенно-специфичным функциям, включающее:

  • Примеры цепочки вызовов метода Send для каждого адаптера
  • Объяснение платформенно-специфичных форматов событий/сообщений

Общие методы использования см. в:


Платформо-специфичные функции

Эта часть поддерживается разработчиками адаптеров и предназначена для описания отличий и расширений адаптера по сравнению со стандартом OneBot12. Пожалуйста, ознакомьтесь с подробной документацией для каждой платформы:

Кроме того, существует адаптер sandbox, но для него не требуется документация по платформо-специфичным функциям


Общие интерфейсы

Chain-вызов Send

Все адаптеры поддерживают следующий стандартный способ вызова:

Важно: {AdapterName} в документации нужно заменить на фактическое имя адаптера (например, yunhu, telegram, onebot11, email и т.д.).

  1. Указание типа и идентификатора: To(type,id).Func()
    # Получение экземпляра адаптера
    my_adapter = adapter.get("{AdapterName}")
    
    # Отправка сообщения
    await my_adapter.Send.To("user", "U1001").Text("Hello")
    
    # Например:
    yunhu = adapter.get("yunhu")
    await yunhu.Send.To("user", "U1001").Text("Hello")
    
  2. Только указание идентификатора: To(id).Func()
    my_adapter = adapter.get("{AdapterName}")
    await my_adapter.Send.To("U1001").Text("Hello")
    
    # Например:
    telegram = adapter.get("telegram")
    await telegram.Send.To("U1001").Text("Hello")
    
  3. Указание отправляющего аккаунта: Using(account_id)
    my_adapter = adapter.get("{AdapterName}")
    await my_adapter.Send.Using("bot1").To("U1001").Text("Hello")
    
    # Например:
    onebot11 = adapter.get("onebot11")
    await onebot11.Send.Using("bot1").To("U1001").Text("Hello")
    
  4. Прямой вызов: Func()
    my_adapter = adapter.get("{AdapterName}")
    await my_adapter.Send.Text("Broadcast message")
    
    # Например:
    email = adapter.get("email")
    await email.Send.Text("Broadcast message")
    

Асинхронная отправка и обработка результатов

Методы Send DSL возвращают объект asyncio.Task, что означает, что вы можете выбрать, нужно ли немедленно ожидать результат:

# Получение экземпляра адаптера
my_adapter = adapter.get("{AdapterName}")

# Не ждать результата, сообщение отправляется в фоне
task = my_adapter.Send.To("user", "123").Text("Hello")

# Если нужно получить результат отправки, можно ожидать позже
result = await task

Декораторы правил отправки

В реальном разработке часто требуется: выполнять последующую логику только после успешной отправки, автоматически повторять отправку при сбое, отменять при таймауте, отслеживать прогресс отправки и т.д. В Send DSL встроена система декораторов правил отправки, которые можно добавлять цепочкой методов:

Метод Описание
.Hook(callback) Выполняется после успешной отправки (можно вызывать несколько раз)
.Retry(times=1) Автоматически повторяет отправку N раз (включая первую, всего N+1 раз)
.Timeout(seconds) Останавливает отправку при превышении времени (можно использовать вместе с Retry)
.Defer(seconds) Откладывает отправку (внутрипроцессное таймерное ожидание, не сохраняется)
.OnProgress(callback) Вызывает обратный вызов на каждом этапе, передаёт SendContext
.OnError(callback) Вызывается при окончательном сбое (вызывается только один раз)
yunhu = adapter.get("yunhu")

# Вычитание баллов только после успешной отправки
await (yunhu.Send.To("user", "123")
       .Hook(lambda r: deduct_points("123"))
       .Text("Успешная покупка"))

# Повтор отправки + отмена при таймауте + отслеживание прогресса
def on_progress(ctx):
    print(f"Этап: {ctx.stage}, Попытка: {ctx.attempt + 1}/{ctx.max_attempts}")

task = (yunhu.Send.To("user", "123")
        .Retry(3)              # Повторяет до 3 раз
        .Timeout(10)           # Каждая отправка имеет таймаут 10 секунд
        .OnProgress(on_progress)
        .OnError(lambda ctx: notify_admin(ctx.error))
        .Text("Важное уведомление"))

Методы правил возвращают self, и их необходимо вызывать до отправки методов (Text/Image и т.д.). SendContext содержит поля stage (pending/sending/retrying/success/failed/timeout), attempt, elapsed, error, result и т.д., что полезно для отслеживания.

Режим построения пакетов (Build)

В одной цепочке можно построить несколько методов отправки, а затем выполнить их все сразу. Подходит для сценариев "отправить несколько сообщений за один раз":

yunhu = adapter.get("yunhu")

# Строим несколько сообщений и отправляем их одновременно
results = await (yunhu.Send.To("user", "123")
                .Build()                     # Переходим в режим построения
                .Text("Уведомление 1")
                .Image("pic.jpg")
                .Text("Уведомление 2")
                .send_all())                 # Выполняем все сообщения
# results = [результат Text, результат Image, результат Text]

.send_all() по умолчанию выполняется параллельно (параллельная отправка, высокая эффективность). Если нужно гарантировать порядок доставки, вызовите .Sequential() для последовательного выполнения:

# Последовательное выполнение (гарантирует порядок) + повтор при сбое
await (yunhu.Send.To("group", "456")
       .Build()
       .Sequential()                # Отправка по порядку
       .Retry(2)                     # Каждая неудачная отправка будет повторена
       .Text("Первое сообщение").Text("Второе сообщение")
       .send_all())

Пакетная отправка использует стратегию "продолжать при сбое": если одна отправка не удалась, это не прерывает другие, и неудачные сообщения автоматически повторяются. Пакетная отправка также поддерживает Hook для всех успешных отправок, OnError при наличии ошибок и OnProgress для обратного вызова о прогрессе.

Подробное описание правил и построения пакетов см. в разделе SendDSL详解.

Обработка событий

Существует три способа обработки событий:

  1. Обработка событий на уровне платформы:

    from ErisPulse.Core import adapter, logger
    
    @adapter.on("event_type", raw=True, platform="{AdapterName}")
    async def handler(data):
        logger.info(f"Получено событие от {AdapterName}: {data}")
    
  2. Обработка стандартных событий OneBot12:

    from ErisPulse.Core import adapter, logger
    
    # Обработка стандартного события OneBot12
    @adapter.on("event_type")
    async def handler(data):
        logger.info(f"Получено стандартное событие: {data}")
    
    # Обработка стандартного события для конкретной платформы
    @adapter.on("event_type", platform="{AdapterName}")
    async def handler(data):
        logger.info(f"Получено событие от {AdapterName}: {data}")
    
  3. Обработка событий через модуль Event: События в модуле Event основаны на функции adapter.on(), поэтому формат событий, предоставляемых Event, соответствует стандарту OneBot12.

    from ErisPulse.Core.Event import message, notice, request, command
    
    message.on_message()(message_handler)
    notice.on_notice()(notice_handler)
    request.on_request()(request_handler)
    command("hello", help="Отправить приветственное сообщение", usage="hello")(command_handler)
    
    async def message_handler(event):
        logger.info(f"Получено сообщение: {event}")
    async def notice_handler(event):
        logger.info(f"Получено уведомление: {event}")
    async def request_handler(event):
        logger.info(f"Получен запрос: {event}")
    async def command_handler(event):
        logger.info(f"Получена команда: {event}")
    

Наиболее рекомендуемый способ обработки событий — использование модуля Event, поскольку он предоставляет богатый набор типов событий и методов обработки.

Стандартный формат

Для удобства справки здесь приведён простой формат событий. Для получения подробной информации, пожалуйста, обратитесь к ссылкам выше.

Примечание: Ниже представлен базовый стандартный формат OneBot12, который может быть дополнен адаптерами. Для получения подробной информации, пожалуйста, обратитесь к описанию специфических функций каждого адаптера.

Стандартный формат событий

Формат преобразования событий, который должен реализовать каждый адаптер:

{
  "id": "event_123",
  "time": 1752241220,
  "type": "message",
  "detail_type": "group",
  "platform": "example_platform",
  "self": {"platform": "example_platform", "user_id": "bot_123"},
  "message_id": "msg_abc",
  "message": [
    {"type": "text", "data": {"text": "Привет"}}
  ],
  "alt_message": "Привет",
  "user_id": "user_456",
  "user_nickname": "ExampleUser",
  "group_id": "group_789"
}

Стандартный формат ответа

Успешная отправка сообщения

{
  "status": "ok",
  "retcode": 0,
  "data": {
    "message_id": "1234",
    "time": 1632847927.599013
  },
  "message_id": "1234",
  "message": "",
  "echo": "1234",
  "{platform}_raw": {...}
}

Неудачная отправка сообщения

{
  "status": "failed",
  "retcode": 10003,
  "data": null,
  "message_id": "",
  "message": "Отсутствуют необходимые параметры",
  "echo": "1234",
  "{platform}_raw": {...}
}

Ссылки

Проект ErisPulse:

Связанная официальная документация:

Участие в разработке

Мы приветствуем больше разработчиков, желающих участвовать в написании и поддержке документации адаптеров! Пожалуйста, выполните следующие шаги, чтобы отправить свой вклад:

  1. Сделайте форк репозитория ErisPuls.
  2. Создайте файл Markdown в каталоге docs/platform-features/ и назовите его в формате <platform-name>.md.
  3. Добавьте ссылку на ваш вклад в адаптер и соответствующую официальную документацию в этот файл README.md.
  4. Отправьте Pull Request.

Благодарим за вашу поддержку!