ErisPulse Request Operation Specification
This document defines the standardized specification for request event operations in the ErisPulse adapter, including the field requirements for request events, the usage of Request DSL, and adapter implementation requirements.
1. Overview
The request event (type: "request") is a special event type defined in the OneBot12 standard, representing a request that requires the Bot to make a decision (such as friend requests or group invitations).
Unlike message events, request events require bidirectional interaction:
- Receiving: The adapter converts the native platform request into a standard request event.
- Responding: The module executes operations through the
RequestDSL orEvent.approve()/Event.reject().
Platform native request event
│
▼
Converter.convert() ← Adapter implementation (forward conversion)
│
▼
Standard request event (with request_id)
│
├─→ Module handler @request.on_friend_request()
│ │
│ ├─→ event.approve() ← Approve the request
│ └─→ event.reject() ← Reject the request
│ │
│ ▼
│ adapter.Request(request_id).accept()
│ │
│ ▼
│ BaseAdapter.Request.accept() ← Adapter override
│ │
│ ▼
│ Platform API call
│
└─→ Or directly through adapter operation
await adapter.Request("req_id").accept()
2. Request Event Field Requirements
2.1 Standard Fields
In addition to the standard OneBot12 fields, the request event must also include the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
request_id |
string | Strongly Recommended | Request identifier, used for approve/reject operations |
user_id |
string | Yes | ID of the requester |
user_nickname |
string | No | Nickname of the requester |
comment |
string | No | Request comment |
2.2 request_id Field
request_id is the core identifier for request operations:
- Purpose: Identifies a request that can be operated on, used by the
RequestDSL - Generation Rules:
- Prefer to use the platform's native request identifier (e.g., OneBot11's
flagfield, Telegram'schat_invite_link, etc.) - If the platform does not have a native request ID, the adapter should generate a unique identifier (recommended format:
platform_timestamp_user_id)
- Prefer to use the platform's native request identifier (e.g., OneBot11's
- Uniqueness: Should be unique within the same platform
- Missing Behavior: When
request_idis missing,event.approve()/event.reject()will raise aValueError
2.3 Request Event Example
{
"id": "evt_123456",
"time": 1752241225,
"type": "request",
"detail_type": "friend",
"platform": "onebot11",
"self": {
"platform": "onebot11",
"user_id": "bot_123"
},
"user_id": "user_456",
"user_nickname": "YingXinche",
"comment": "Please add as a friend",
"request_id": "flag_abc123",
"onebot11_raw": {...},
"onebot11_raw_type": "request"
}
3. Request DSL
3.1 Method Chaining
The Request class provides a method chaining interface consistent with the Send style:
# Basic usage
await adapter.Request("req_id").accept()
await adapter.Request("req_id").reject()
# Specify Bot account
await adapter.Request("req_id").Using("bot1").accept()
# Attach remarks (via kwargs)
await adapter.Request("req_id").accept(comment="Welcome")
await adapter.Request("req_id").reject(comment="Temporarily not adding")
# Combinatorial usage
await adapter.Request("req_id").Using("bot1").accept(comment="Welcome")
3.2 Method List
| Method | Description | Return Value |
|---|---|---|
Using(account_id) |
Specify the Bot account to perform the operation | RequestDSL (supports method chaining) |
accept(**kwargs) |
Accept the request | asyncio.Task (await returns standard response) |
reject(**kwargs) |
Reject the request | asyncio.Task (await returns standard response) |
3.3 Return Value Format
The operation returns a standard API response format:
Success:
{
"status": "ok",
"retcode": 0,
"data": null,
"message_id": "",
"message": ""
}
Failure:
{
"status": "failed",
"retcode": 34001,
"data": null,
"message_id": "",
"message": "Request has expired or does not exist"
}
Not Implemented (adapter did not override accept/reject):
{
"status": "failed",
"retcode": 10002,
"data": null,
"message_id": "",
"message": "Platform MyAdapter does not implement request operation (accept)"
}
4. Event Convenience Methods
The Event wrapper class provides convenience methods suitable for use in request event handlers:
from ErisPulse.Core.Event import request
@request.on_friend_request()
async def handle_friend_request(event):
# Get the request ID
request_id = event.get_request_id()
if not request_id:
print("Warning: Request event missing request_id")
return
# Approve the request
result = await event.approve()
# Or reject the request
# result = await event.reject(comment="Temporarily not adding friends")
# Check the result
if result.get("status") == "ok":
print("Operation successful")
else:
print(f"Operation failed: {result.get('message')}")
4.1 Event Method List
| Method | Description | Return Value |
|---|---|---|
get_request_id() |
Get the request ID | str |
approve(comment=None) |
Approve the current request event | Standard response format |
reject(comment=None) |
Reject the current request event | Standard response format |
5. Adapter Implementation Requirements
5.1 Converter Requirements
The adapter's converter must correctly set the request_id field when converting request events:
def convert_request_event(self, raw_event: dict) -> dict:
"""Convert platform-native request events"""
return {
"id": self._generate_event_id(raw_event),
"time": int(time.time()),
"type": "request",
"detail_type": self._map_request_type(raw_event), # "friend" or "group"
"platform": self._platform_name,
"self": {
"platform": self._platform_name,
"user_id": str(self._bot_id),
},
"user_id": str(raw_event.get("user_id", "")),
"user_nickname": raw_event.get("nickname", ""),
"comment": raw_event.get("message", ""),
"request_id": self._extract_request_id(raw_event), # ← Key field
f"{self._platform_name}_raw": raw_event,
f"{self._platform_name}_raw_type": raw_event.get("type", ""),
}
def _extract_request_id(self, raw_event: dict) -> str:
"""
Extract request ID from platform-native event
Prefer native platform request identifier; generate unique ID if not available
"""
# Prefer native platform ID
if flag := raw_event.get("flag"):
return str(flag)
if request_key := raw_event.get("request_key"):
return str(request_key)
# Fallback: generate unique ID
import hashlib
raw = f"{self._platform_name}_{raw_event.get('user_id')}_{raw_event.get('timestamp')}"
return hashlib.md5(raw.encode()).hexdigest()
5.2 Request Inner Class Implementation
The adapter can implement accept and reject methods in the Request inner class:
from ErisPulse.Core import BaseAdapter, RequestDSL
class MyAdapter(BaseAdapter):
class Request(RequestDSL):
"""MyPlatform request operation implementation"""
def accept(self, **kwargs):
"""
Approve request
:param kwargs: Additional parameters, such as comment="备注"
:return: asyncio.Task
"""
async def _do():
try:
result = await self._adapter.call_api(
endpoint="/set_request",
request_id=self._request_id,
approve=True,
**kwargs,
)
return {
"status": "ok" if result.get("code") == 0 else "failed",
"retcode": result.get("code", 0),
"data": None,
"message_id": "",
"message": result.get("message", ""),
}
except Exception as e:
return {
"status": "failed",
"retcode": 34001,
"data": None,
"message_id": "",
"message": f"Request operation failed: {e}",
}
return self._create_task(_do())
def reject(self, **kwargs):
"""Reject request"""
async def _do():
try:
result = await self._adapter.call_api(
endpoint="/set_request",
request_id=self._request_id,
approve=False,
**kwargs,
)
return {
"status": "ok" if result.get("code") == 0 else "failed",
"retcode": result.get("code", 0),
"data": None,
"message_id": "",
"message": result.get("message", ""),
}
except Exception as e:
return {
"status": "failed",
"retcode": 34001,
"data": None,
"message_id": "",
"message": f"Request operation failed: {e}",
}
return self._create_task(_do())
5.3 Platform Does Not Support Request Operations
If the platform does not support friend requests/group invitations (e.g., some platforms handle requests automatically), the adapter can:
- Do not override the
Requestinner class: Use the default implementation from the base class, returningretcode=10002when callingaccept()/reject() - Skip generating
request_idduring conversion: Do not generaterequest_id, causingevent.approve()to raiseValueError - Log warnings: Record warnings in
accept/rejectand return appropriate error codes
5.4 Summary: Send and Request in Parallel
The adapter has two parallel DSL inner classes, each with distinct responsibilities:
BaseAdapter
├── Send(SendDSL) ← Message sending
│ ├── Raw_ob12() ← Must be implemented
│ ├── Text() ← Recommended implementation
│ └── Image() ← Implemented as needed
│
└── Request(RequestDSL) ← Request operations
├── accept() ← Implemented as needed
└── reject() ← Implemented as needed
5.5 Adapter __init__ Considerations
When overriding the Request inner class's __init__, ensure that parameters are passed through and super().__init__() is called. See Adapter Development Introduction - __init__ Considerations (Request is similar, with parameters adapter, request_id, account_id).
6. Adapter Implementation Checklist
Basic Requirements
- If
__init__is overridden,super().__init__()has been called (to ensure Send / Request factory initialization)
Request Event Transformation
- The request event includes the
request_idfield (strongly recommended) -
detail_typeis correctly mapped to"friend"or"group" - Platform raw data is preserved in the
{platform}_rawfield - The
request_idgeneration rule is documented
Request Handling
- The
Requestinner class is implemented (if the platform supports request operations) - The
accept()method is implemented - The
reject()method is implemented - The operation returns a standard API response format
- Unsupported operations return
retcode=10002 - Network errors return
retcode=33xxx(following the API response standard)
7. Error Code Extension
The adapter implementation layer related to request operations recommends error codes (following API Response Standard §3.2, falling within the low three digits of the 34xxx platform error segment for customization):
| Error Code | Error Name | Description |
|---|---|---|
| 34001 | Request Not Found | The request does not exist or has expired |
| 34002 | Request Already Handled | The request has already been processed |
| 34003 | Request Not Supported | The platform does not support this type of request operation |
| 34004 | Permission Denied | The Bot is not authorized to process this request (returned by the platform) |
Boundary with Framework Code: The above
340xxcodes indicate request processing failures returned by the platform/adapter;
When the ErisPulse framework disables a module'srequestaction inscope.actions, it directly returns34601(Action Denied) (see API Response Standard §5.3) before calling the adapter.
The two are not mutually replaceable: first pass through the34601framework gate, then fall into the platform layer340xxerror.
8. Related Documents
- Event Conversion Standard - Complete event conversion specification
- API Response Standard - Adapter API response format standard
- Send Method Specification - Naming and parameter specification for Send class methods
- Session Type Standard - Definition and mapping relationships of session types