Event Wrapper Class Detailed Explanation
The Event module provides a powerful Event wrapper class that simplifies event handling.
Adding Type Annotations to the event Parameter
The event parameter in event handlers is an Event wrapper class (a subclass of dict). It is strongly recommended to add type annotations to it:
from ErisPulse.Core.Event import Event
@message.on_private_message()
async def handler(event: Event):
text = event.get_text() # IDE auto-completes all convenient methods
await event.reply(text) # Spelling errors are detected during static checking
Without annotations, the IDE cannot recognize methods on Event (get_text() / reply() / wait_reply() / platform extension methods are not suggested), and you must rely on memory for spelling.
Note: The
eventin event handler callbacks is an Event wrapper class (annotated asEvent); in module lifecycle methodson_load/on_unload, theeventis a regular dict (annotated asdict), and these should not be confused.
Core Features
- Fully compatible with dictionaries: Event inherits from dict
- Convenient methods: Provides a large number of convenient methods
- Dot-style access: Supports accessing event fields using dot notation
- Backward compatibility: All methods are optional
Core Field Methods
from ErisPulse.Core.Event import command
@command("info")
async def info_command(event: Event):
event_id = event.get_id()
platform = event.get_platform()
time = event.get_time()
print(f"ID: {event_id}, Platform: {platform}, Time: {time}")
Message Event Methods
from ErisPulse.Core.Event import message
@message.on_private_message()
async def private_handler(event: Event):
text = event.get_text()
user_id = event.get_user_id()
nickname = event.get_user_nickname()
await event.reply(f"Hello, {nickname}!")
Message Type Detection
from ErisPulse.Core.Event import message
@message.on_group_message()
async def group_handler(event: Event):
is_private = event.is_private_message()
is_group = event.is_group_message()
is_at = event.is_at_message()
await event.reply(f"Type: {'Private' if is_private else 'Group'}")
Reply Functionality
from ErisPulse.Core.Event import command
@command("ask")
async def ask_command(event: Event):
await event.reply("Please enter your name:")
reply = await event.wait_reply(timeout=30)
if reply:
name = reply.get_text()
await event.reply(f"Hello, {name}!")
@command("price")
async def price_command(event: Event):
await event.reply("Please enter the amount (e.g., 5 yuan):")
# Reply must match the regex, otherwise continue waiting until timeout
reply = await event.wait_reply(timeout=30, regex=r"\d+\s*元")
if reply:
await event.reply(f"Received amount: {reply.get_text()}")
Advanced Conversation Capabilities
Note
This section requires ErisPulse 2.8.0+.
# Session timeout reminder: Remind after 5 minutes of no reply, user reply cancels automatically
reminder = event.remind(300, "Are you still there? Reply 'exit' if you don't want to chat")
reminder.cancel() # Can also be manually canceled
# Escalation: Guaranteed arrival at the deadline (not canceled by reply), e.g., notify the owner if long-term unhandled
event.escalate(1800, lambda e: notify_master("Ticket timeout"))
# Multi-path waiting: Wait for "agree" and "reject" simultaneously, first to arrive wins
which, reply = await event.select(
event.expect(pattern="agree*", user="10001"),
event.expect(pattern="reject*", user="10002"),
timeout=60,
)
if which is None:
await event.reply("No approval received within timeout")
# Session-level waiting: Any reply from the same group can match (group collaboration)
reply = await event.wait_reply(session=True, prompt="Any expert, please answer?")
# Session inbox: Recent 20 messages in the current session (including bot, AI context / anti-spam base)
messages = await event.history(20)
# Message transaction: Automatically recall messages sent within the transaction on exception
async with event.message_tx():
await event.reply("Processing, please wait...")
result = await do_something()
await event.reply(f"Completed: {result}")
Command Information Retrieval
from ErisPulse.Core.Event import command
@command("cmdinfo")
async def cmdinfo_command(event: Event):
cmd_name = event.get_command_name()
cmd_args = event.get_command_args()
await event.reply(f"Command: {cmd_name}, Args: {cmd_args}")
Notice Event Methods
from ErisPulse.Core.Event import notice
@notice.on_friend_add()
async def friend_add_handler(event: Event):
await event.reply("Welcome to add me as a friend!")
Method Quick Reference
Core Methods
Event Basic Information
get_id()- Get event IDget_time()- Get event timestamp (Unix seconds)get_type()- Get event type (message/notice/request/meta)get_detail_type()- Get detailed event type (private/group/friend etc.)get_platform()- Get platform name
Bot Information
get_self_platform()- Get bot platform nameget_self_user_id()- Get bot user IDget_self_account_id()- Get bot account ID (multi-bot mode)get_self_info()- Get full bot information as a dictionary
Session Identifiers
get_target_id()- Get unified target ID (returnsgroup_idfor group chats,channel_idfor channels,user_idfor private chats, first non-empty value in order group → channel → guild → thread → user)get_session_id()- Get unique session identifier, format:{platform}:{detail_type}:{target_id}
Message Event Methods
Message Content
get_message()- Get message segment array (OneBot12 format)get_alt_message()- Get alternate message textget_text()- Get plain text content (get_alt_message()alias)get_message_text()- Get plain text content (get_alt_message()alias)
Sender Information
get_user_id()- Get sender user IDget_user_nickname()- Get sender nicknameget_sender()- Get sender full information as a dictionary
Group/Channel Information
get_group_id()- Get group ID (group chat messages)get_channel_id()- Get channel ID (channel messages)get_guild_id()- Get server ID (server messages)get_thread_id()- Get topic/subchannel ID (topic messages)
@Message Related
has_mention()- Whether the message contains @botget_mentions()- Get list of all mentioned user IDs
Message Type Detection
Basic Detection
is_message()- Whether it is a message eventis_private_message()- Whether it is a private messageis_group_message()- Whether it is a group messageis_at_message()- Whether it is an @message (has_mention()alias)
Notice Event Methods
Notice Operator
get_operator_id()- Get operator IDget_operator_nickname()- Get operator nickname
Notice Type Detection
is_notice()- Whether it is a notice eventis_group_member_increase()- Group member increase eventis_group_member_decrease()- Group member decrease eventis_friend_add()- Friend add event (matchesdetail_type == "friend_increase")is_friend_delete()- Friend delete event (matchesdetail_type == "friend_decrease")
Request Event Methods
Request Information
get_comment()- Get request comment
Request Type Detection
is_request()- Whether it is a request eventis_friend_request()- Whether it is a friend requestis_group_request()- Whether it is a group request
Reply Functionality
Basic Reply
reply(content, method="Text", at_sender=False, quote=False, at_users=None, reply_to=None, at_all=False, via=None, **kwargs)- General reply methodcontent: Content to send (text, URL, etc.)method: Sending method, default "Text", optional "Image"/"Voice"/"Video"/"File" etc.at_sender: Whether to @ sender (auto-extract user_id)quote: Whether to quote reply to current message (auto-extract message_id)at_users: List of users to @, e.g.["user1", "user2"]reply_to: Manually specify the message ID to reply toat_all: Whether to @ all members**kwargs: Additional parameters (e.g., user_id for Mention method)
reply_ob12(message)- Reply using OneBot12 message segmentsmessage: OneBot12 message segment list or dictionary, can be built with MessageBuilder
Platform Capability Query
supports(method)- Check if the current platform supports a sending method (e.g.,"Image","Voice"), returnsboolavailable_methods()- List all available sending methods on the current platform, returns a list of method names
Forward Functionality
Note: Forward functionality must be implemented through the adapter's Send DSL; the Event wrapper class itself does not provide a direct forward method.
# Forward message to group
adapter = sdk.adapter.get(event.get_platform())
target_id = event.get_group_id() # Or specify another group ID
await adapter.Send.To("group", target_id).Text(event.get_text())
Wait Reply Functionality
wait_reply(prompt=None, timeout=60.0, callback=None, validator=None, method="Text", pattern=None, regex=None)- Wait for user replyprompt: Prompt message, if provided will be sent to the usertimeout: Wait timeout time (seconds), default 60 secondscallback: Callback function, executed when reply is receivedvalidator: Validation function, used to validate if the reply is validmethod: Sending method for the prompt, default "Text"pattern: Glob wildcard (*/?/[seq]), reply text must match, otherwise continue waitingregex: Regular expression, reply text must match (eitherpatternorregex), otherwise continue waiting- Returns the user's reply as an Event object, returns None on timeout
Interactive Methods
confirm(prompt=None, timeout=60.0, yes_words=None, no_words=None, method="Text", hint=False)- Confirmation dialog- Returns
True(confirmed) /False(rejected) /None(timeout) - Built-in Chinese and English confirmation words are automatically recognized, custom word sets can be provided
method: Sending method, default "Text"; supports "Image"/"Markdown" etc. for non-text promptshint: Whether to automatically append confirmation word prompt at the end of the prompt (e.g., "(Yes/No)"), default False
- Returns
choose(prompt, options, timeout=60.0, method="Text", options_format="auto", merge_prompt=False, placeholder="{options}")- Selection menuoptions: List of option texts- Returns the option index (0-based), returns
Noneon timeout method: Sending method, default "Text"; text-based methods (Text/Markdown/md/Html/h5) automatically merge options to the endoptions_format: Option format (default: "auto", automatically selects built-in style based on method)"auto": Markdown→unordered list (- 1. Option), Html→ordered list (<ol>), others→plain text list"list": One per line, e.g.1. Option A\n2. Option B"inline": Display in a single line, e.g.1.A | 2.B"md": Markdown unordered list"html": Html ordered listcallable: Custom function, receiveslist[str]and returnsstr
merge_prompt: Whether to forcibly merge into a single message, default FalseFalse(default): Text-based methods automatically merge; non-text methods send prompt first, then send Text optionsTrue: Regardless of method, always merge into a single message, sent using the specified method
placeholder: Option insertion placeholder, default{options}; the position of this marker in the prompt is replaced with the option text, set to empty string to always append to the end
collect(fields, timeout_per_field=60.0)- Form collectionfields: List of fields, each containingkey,prompt, optionalvalidator, optionalmethod- Returns
{key: value}dictionary, returnsNoneif any field times out - Each field supports
methodkey to specify sending method, e.g., collecting images with{"key": "avatar", "prompt": "Please send avatar", "method": "Image"} - Each field can have an optional
optionskey (list), when provided, the field becomes a multiple-choice question (automatically uses choose logic) - Each field can have optional
options_format,merge_prompt,placeholderkeys to control option format, message merging behavior, and placeholder
wait_for(event_type="message", condition=None, timeout=60.0)- Wait for any eventcondition: Filter function, returnsTruewhen matched- Returns the matching Event object, returns
Noneon timeout
conversation(timeout=60.0)- Create multi-turn conversation context- Returns a
Conversationobject, supportingsay()/wait()/confirm()/choose()/collect()/stop() is_activeattribute indicates whether the conversation is active
- Returns a
Interactive Method Examples
confirm() - Confirmation Dialog:
@command("delete", help="Delete data")
async def delete_handler(event: Event):
if await event.confirm("Are you sure you want to delete all data?"):
sdk.storage.delete("all_data")
await event.reply("Data has been deleted")
else:
await event.reply("Cancelled")
confirm() - With Prompt Words:
# hint=True appends "(Yes/No)" at the end of the prompt
if await event.confirm("Continue?", hint=True):
await event.reply("Continued")
# User sees: Continue? (Yes/No)
choose() - Selection Menu:
@command("color", help="Choose color")
async def color_handler(event: Event):
choice = await event.choose("Please choose a color:", ["Red", "Green", "Blue"])
if choice is not None:
colors = ["Red", "Green", "Blue"]
await event.reply(f"You chose: {colors[choice]}")
choose() - Option Formatting and Message Merging:
# inline format: options displayed in a single line
choice = await event.choose("Please choose:", ["A", "B", "C"], options_format="inline")
# Output: 1.A | 2.B | 3.C
# Custom format
choice = await event.choose("Please choose:", ["Cat", "Dog"],
options_format=lambda opts: " / ".join(opts))
# Output: Cat / Dog
# options_format="auto" (default): Automatically selects built-in style based on method
# Markdown → unordered list
choice = await event.choose(
"## Please choose", ["Cat", "Dog"],
method="Markdown", # auto recognizes as md list
)
# Output:
# ## Please choose
# - 1. Cat
# - 2. Dog
# Html → ordered list
choice = await event.choose(
"<h2>Please choose</h2>", ["Cat", "Dog"],
method="Html", merge_prompt=True, # auto recognizes as html list
)
# Output:
# <h2>Please choose</h2>
# <ol><li>1. Cat</li><li>2. Dog</li></ol>
# Merge mode + placeholder
choice = await event.choose(
"## Please choose\n{options}\nPlease reply with number",
["Cat", "Dog"],
method="Markdown", merge_prompt=True,
)
# Custom placeholder
choice = await event.choose(
"Choose: [choices]",
["Cat", "Dog"],
placeholder="[choices]",
)
collect() - Form Collection:
@command("register", help="Register")
async def register_handler(event: Event):
data = await event.collect([
{"key": "name", "prompt": "Please enter your name:"},
{"key": "age", "prompt": "Please enter your age:",
"validator": lambda e: e.get_text().isdigit()},
])
if data:
await event.reply(f"Registration successful! {data['name']}, {data['age']} years old")
Non-Text Methods in reply:
await event.reply("http://example.com/img.jpg", method="Image")
await event.reply("http://example.com/audio.mp3", method="Voice")
from ErisPulse.Core.Event import MessageBuilder
segments = MessageBuilder.text("Look at this image:").image("http://example.com/img.jpg").build()
await event.reply_ob12(segments)
For complete Conversation multi-turn dialog usage, see Conversation Multi-turn Dialog.
Command Information
Command Basics
get_command_name()- Get command nameget_command_args()- Get command argument listget_command_raw()- Get raw command textget_command_info()- Get full command information as a dictionaryis_command()- Whether it is a command
Raw Data
get_raw()- Get raw platform event dataget_raw_type()- Get raw platform event type
Platform Extension Methods
Adapters can register platform-specific methods for the Event wrapper class. The methods are only available on Event instances of the corresponding platform; attempting to access them on other platforms raises AttributeError.
Platform methods take precedence over built-in methods via Event.__getattribute__, allowing them to override built-in interactive methods like confirm, choose, collect, wait_reply, providing platform-specific implementations (e.g., buttons, cards). Built-in implementations are exported as _builtin_* functions for overriding.
# Email event - only email methods
event = Event({"platform": "email", "email_raw": {"subject": "Hello"}})
event.get_subject() # ✅ Returns "Hello"
event.get_chat_type() # ❌ AttributeError
# Telegram event - only Telegram methods
event = Event({"platform": "telegram", "telegram_raw": {"chat": {"type": "private"}}})
event.get_chat_type() # ✅ Returns "private"
event.get_subject() # ❌ AttributeError
# Built-in methods are always available
event.get_text() # ✅ Any platform
event.reply("hi") # ✅ Any platform
Query Registered Methods
from ErisPulse.Core.Event import get_platform_event_methods
methods = get_platform_event_methods("email")
# ["get_subject", "get_from", ...]
hasattr and dir Support
hasattr(event, "get_subject") # Returns True only when platform="email"
"get_subject" in dir(event) # Same as above
Cross-platform Extension (Wildcard)
register_event_method and register_event_mixin support passing "*" as the platform name, registering methods available on Event instances of all platforms. This is suitable for AI chat, context management, and other features requiring cross-platform reuse.
from ErisPulse.Core.Event.wrapper import register_event_method
@register_event_method("*")
async def ai_chat(self, prompt: str):
# self is an Event instance, can access event data and built-in methods
await self.reply(f"AI: {prompt}")
After registration, event.ai_chat(...) can be called from any platform's event handler.
Method resolution priority (from highest to lowest): platform-specific methods → wildcard methods → built-in methods → dictionary key access.
For adapter developers registering extension methods, see Event System API - Cross-platform Extension Wildcard.
Related Documentation
- Module Development Getting Started - Create your first module
- Best Practices - Develop high-quality modules