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

Kook Platform Features Documentation

KookAdapter is an adapter built on the Kook (Kaihei La) Bot WebSocket protocol, integrating all Kook functionality modules and providing a unified interface for event handling and message operations.


Document Information

Basic Information

Configuration

KookAdapter supports multi-account configuration, where each account corresponds to an independent Kook bot.

# config.toml
# Account 1
[KookAdapter.accounts.default]
token = "YOUR_BOT_TOKEN"     # Kook Bot Token (required, format: Bot xxx/xxx)
bot_id = ""                   # Bot User ID (optional, if not set, it will be parsed from token)
compress = true               # Whether to enable WebSocket compression (optional, default is true)
enabled = true                # Whether to enable this account (optional, default is true)

# Account 2
[KookAdapter.accounts.bot2]
token = "ANOTHER_BOT_TOKEN"
bot_id = ""
enabled = true

Compatibility with old configurations: If an old single-account [KookAdapter] configuration (including token) is detected, it will be automatically migrated to accounts.default.

Configuration item description (per account):

API Environment:

v5 Paradigm Update (4.1.0)

This adapter has completed alignment with the v5 paradigm (incremental upgrade, API compatible):

Standard API Actions

from ErisPulse import sdk
kook = sdk.adapter.get("kook")

result = await kook.Api.get_self_info()              # GET /users/@me
result = await kook.Api.get_user_info(user_id)       # POST /user/view
result = await kook.Api.get_guild_info(guild_id)     # POST /guild/view
result = await kook.Api.get_guild_list()             # POST /guild/list
result = await kook.Api.get_channel_info(channel_id) # POST /channel/view
result = await kook.Api.get_channel_list(guild_id)   # POST /channel/list
await kook.Api.delete_message(msg_id)                # POST /message/delete
result = await kook.Api.Using("main").get_self_info()

Buttons (keyboard)

rows = [[{"label": "Option A", "type": "callback", "data": "vote:A"},
         {"label": "Website",  "type": "link",     "data": "https://example.com"}]]
await kook.Send.To("channel", channel_id).Keyboard(rows).Text("Please select")
# Text and buttons automatically combine into Kook card messages (section + action-group)

# Button click callback (standard fields)
from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_button(event):
    if event.get("platform") == "kook" and event.get("button_data"):
        data = event["button_data"]

Supported Message Sending Types

All sending methods are implemented through a fluent API syntax, for example:

from ErisPulse.Core import adapter
kook = adapter.get("kook")

await kook.Send.To("group", channel_id).Text("Hello World!")

The supported sending types include:

Fluent Modifier Methods (Can Be Combined)

Modifier methods return self and support fluent chaining, which must be called before the final sending method:

Fluent Chaining Examples

# Basic sending
await kook.Send.To("group", channel_id).Text("Hello")

# Reply to a message
await kook.Send.To("group", channel_id).Reply(msg_id).Text("Replied message")

# Mention a user
await kook.Send.To("group", channel_id).At("user_id").Text("Hello")

# Mention multiple users
await kook.Send.To("group", channel_id).At("user1").At("user2").Text("Multiple users @")

# Mention everyone
await kook.Send.To("group", channel_id).AtAll().Text("Announcement")

# Combine methods
await kook.Send.To("group", channel_id).Reply(msg_id).At("user_id").Text("Composite message")

OneBot12 Message Support

The adapter supports sending OneBot12 formatted messages for cross-platform message compatibility:

# Send a OneBot12 formatted message
ob12_msg = [{"type": "text", "data": {"text": "Hello"}}]
await kook.Send.To("group", channel_id).Raw_ob12(ob12_msg)

# Combine with fluent modifiers
ob12_msg = [{"type": "text", "data": {"text": "Replied message"}}]
await kook.Send.To("group", channel_id).Reply(msg_id).Raw_ob12(ob12_msg)

# Use mention and reply message segments within Raw_ob12
ob12_msg = [
    {"type": "text", "data": {"text": "Hello "}},
    {"type": "mention", "data": {"user_id": "user_id"}},
    {"type": "reply", "data": {"message_id": "msg_id"}}
]
await kook.Send.To("group", channel_id).Raw_ob12(ob12_msg)

Additional Operation Methods

In addition to sending messages, the Kook adapter supports the following operations:

# Edit a message (supports only KMarkdown type=9 and CardMessage type=10)
await kook.Send.To("group", channel_id).Edit(msg_id, "**Updated content**")

# Recall a message
await kook.Send.To("group", channel_id).Recall(msg_id)

# Upload a file (get file URL)
result = await kook.Send.Upload("C:/path/to/file.jpg")
file_url = result["data"]["url"]

Return Values of Send Methods

All send methods return a Task object, which can be awaited directly to obtain the send result. The returned result follows the ErisPulse adapter's standardized return specification:

{
    "status": "ok",           // Execution status: "ok" or "failed"
    "retcode": 0,             // Return code (Kook API's code)
    "data": {...},            // Response data
    "message_id": "xxx",      // Message ID
    "message": "",            // Error message
    "kook_raw": {...}         // Raw response data
}

Error Code Explanation

retcode Description
0 Success
40100 Invalid or missing Token
40101 Token expired
40102 Token does not match Bot
40103 Missing permissions
40000 Invalid parameter
40400 Target does not exist
40300 No permission to perform operation
50000 Internal server error
-1 Internal adapter error

Platform-specific Event Types

Use platform=="kook" to detect and utilize platform-specific features.

Core Differences

  1. Channel System: Kook uses a two-tier structure of servers (Guild) and channels (Channel), with channels serving as the basic message sending targets.
  2. Message Types: Kook supports various message types, including text (1), image (2), video (3), file (4), voice (8), KMarkdown (9), and card messages (10).
  3. Private Messaging System: Kook distinguishes between channel messages and private messages, using different API endpoints.
  4. Message Sequence Numbers: Kook's WebSocket uses sn sequence numbers to ensure message ordering, supporting message buffering and out-of-order reordering.
  5. Message Editing and Deletion: Supports editing sent messages (only KMarkdown and CardMessage) and deleting messages.

Extended Fields

Special Field Examples

# Channel text message
{
  "type": "message",
  "detail_type": "group",
  "user_id": "User ID",
  "group_id": "Channel ID",
  "channel_id": "Channel ID",
  "message_id": "Message ID",
  "kook_raw": {...},
  "kook_raw_type": "1",
  "message": [
    {"type": "text", "data": {"text": "Hello"}}
  ],
  "alt_message": "Hello"
}

# Message with image
{
  "type": "message",
  "detail_type": "group",
  "user_id": "User ID",
  "group_id": "Channel ID",
  "channel_id": "Channel ID",
  "message_id": "Message ID",
  "kook_raw": {...},
  "kook_raw_type": "2",
  "message": [
    {"type": "image", "data": {"file": "Image URL", "url": "Image URL"}}
  ],
  "alt_message": "Image content"
}

# KMarkdown message
{
  "type": "message",
  "detail_type": "group",
  "user_id": "User ID",
  "group_id": "Channel ID",
  "message_id": "Message ID",
  "kook_raw": {...},
  "kook_raw_type": "9",
  "message": [
    {"type": "text", "data": {"text": "Parsed plain text"}}
  ]
}

# Card message
{
  "type": "message",
  "detail_type": "group",
  "user_id": "User ID",
  "group_id": "Channel ID",
  "message_id": "Message ID",
  "kook_raw": {...},
  "kook_raw_type": "10",
  "message": [
    {"type": "json", "data": {"data": "Card JSON content"}}
  ]
}

# Private chat message
{
  "type": "message",
  "detail_type": "private",
  "user_id": "User ID",
  "message_id": "Message ID",
  "kook_raw": {...},
  "kook_raw_type": "1",
  "message": [
    {"type": "text", "data": {"text": "Private chat content"}}
  ]
}

Message Segment Types

Kook's message types are automatically converted to corresponding message segments based on the type field:

Kook type Converted Type Description
1 text Text message
2 image Image message
3 video Video message
4 file File message
8 record Voice message
9 text KMarkdown message (extract plain text content)
10 json Card message (original JSON)

Message segment structure example:

{
  "type": "image",
  "data": {
    "file": "Image URL",
    "url": "Image URL"
  }
}

Mention Message Segment

When a message contains @ information, a mention message segment is inserted before the message segment:

{
  "type": "mention",
  "data": {
    "user_id": "Mentioned User ID"
  }
}

mention_all Message Segment

When a message is a mention to all, a mention_all message segment is inserted:

{
  "type": "mention_all",
  "data": {}
}

WebSocket Connection

Connection Flow

  1. Use the Bot Token to call POST /gateway/index to obtain the WebSocket gateway address.
  2. Connect to the WebSocket gateway.
  3. Upon receiving the HELLO (s=1) signal, verify the connection status.
  4. Begin the heartbeat loop (PING, s=2, sent every 30 seconds).
  5. Receive message events (s=0), using the sn sequence number to ensure order.
  6. Receive the heartbeat response PONG (s=3).

Signal Types

Signal s Value Description
HELLO 1 Server welcome signal, received after successful connection.
PING 2 Client heartbeat, sent every 30 seconds, includes the current sn.
PONG 3 Heartbeat response.
RESUME 4 Resume connection signal, includes sn to resume session.
RECONNECT 5 Server requests reconnection, requires obtaining a new gateway.
RESUME_ACK 6 Response indicating successful RESUME.

Disconnection and Reconnection

Message Sequence Number Mechanism

Kook WebSocket uses sn (incrementing sequence number) to ensure message order:

Usage Examples

Handling Channel Messages

from ErisPulse.Core.Event import message
from ErisPulse import sdk

kook = sdk.adapter.get("kook")

@message.on_message()
async def handle_group_msg(event):
    if event.get("platform") != "kook":
        return
    if event.get("detail_type") != "group":
        return

    text = event.get_text()
    channel_id = event.get("group_id")

    if text == "hello":
        await kook.Send.To("group", channel_id).Text("Hello!")

Handling Private Messages

@message.on_message()
async def handle_private_msg(event):
    if event.get("platform") != "kook":
        return
    if event.get("detail_type") != "private":
        return

    text = event.get_text()
    user_id = event.get("user_id")

    await kook.Send.To("user", user_id).Text(f"You said: {text}")

Handling Notification Events (like emoji reactions)

from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_notice(event):
    if event.get("platform") != "kook":
        return

    sub_type = event.get("sub_type")

    if sub_type == "added_reaction":
        emoji = event.get("emoji", {})
        user_id = event.get("user_id")
        msg_id = event.get("message_id")
        print(f"User {user_id} added an emoji reaction to message {msg_id}")

    elif sub_type == "deleted_reaction":
        emoji = event.get("emoji", {})
        user_id = event.get("user_id")
        msg_id = event.get("message_id")
        print(f"User {user_id} removed an emoji reaction from message {msg_id}")

Sending Media Messages

# Sending an image (URL)
await kook.Send.To("group", channel_id).Image("https://example.com/image.png")

# Sending an image (binary)
with open("image.png", "rb") as f:
    image_bytes = f.read()
await kook.Send.To("group", channel_id).Image(image_bytes)

# Sending a video
await kook.Send.To("group", channel_id).Video("https://example.com/video.mp4")

# Sending a file
await kook.Send.To("group", channel_id).File("https://example.com/file.pdf", filename="document.pdf")

# Sending a voice message
await kook.Send.To("group", channel_id).Voice("https://example.com/voice.mp3")

Sending KMarkdown and Card Messages

# KMarkdown
await kook.Send.To("group", channel_id).Markdown("**Bold** *Italic* [Link](https://example.com)")

# Card message
card = {
    "type": "card",
    "theme": "primary",
    "size": "lg",
    "modules": [
        {"type": "header", "text": {"type": "plain-text", "content": "Title"}},
        {"type": "section", "text": {"type": "kmarkdown", "content": "Content"}}
    ]
}
await kook.Send.To("group", channel_id).Card(card)

Editing and Deleting Messages

# Sending a message
result = await kook.Send.To("group", channel_id).Markdown("**Original content**")
msg_id = result["data"]["msg_id"]

# Editing a message (only supports KMarkdown and CardMessage)
await kook.Send.To("group", channel_id).Edit(msg_id, "**Updated content**")

# Deleting a message
await kook.Send.To("group", channel_id).Recall(msg_id)

Handling Edit and Delete Notifications for Private Messages

@notice.on_notice()
async def handle_private_notice(event):
    if event.get("platform") != "kook":
        return

    sub_type = event.get("sub_type")

    if sub_type == "updated_private_message":
        msg_id = event.get("message_id")
        content = event.get("content")
        print(f"Private message updated: {msg_id}, New content: {content}")

    elif sub_type == "deleted_private_message":
        msg_id = event.get("message_id")
        print(f"Private message deleted: {msg_id}")