qqbotsdk-base-py 2.1.0__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/PKG-INFO +1 -1
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/pyproject.toml +1 -1
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/pyproject.toml.orig +1 -1
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/api/core.py +18 -2
- qqbotsdk_base_py-2.1.0/src/qqbotsdk/errors.py → qqbotsdk_base_py-2.2.0/src/qqbotsdk/errors/__init__.py +10 -0
- qqbotsdk_base_py-2.2.0/src/qqbotsdk/errors/codes.py +129 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/model/sub/messages.py +69 -5
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/ws/__init__.py +5 -3
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/ws/client.py +25 -1
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/ws/intents.py +14 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/README.md +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/api/agent.md +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/api/auth.py +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/api/gateway.py +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/model/agent.md +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/model/core.py +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/model/sub/upload.py +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/ws/agent.md +0 -0
- {qqbotsdk_base_py-2.1.0 → qqbotsdk_base_py-2.2.0}/src/qqbotsdk/ws/payload.py +0 -0
|
@@ -415,8 +415,24 @@ class QQBotSession:
|
|
|
415
415
|
return self._ensure()
|
|
416
416
|
|
|
417
417
|
async def request(self, method: str, url: str, **kwargs: Any) -> ClientResponse:
|
|
418
|
-
"""
|
|
419
|
-
|
|
418
|
+
"""通用 verb 请求: 与 ``get`` / ``post`` 等完全同构, 同样走 429 重试.
|
|
419
|
+
|
|
420
|
+
``method`` 可以是任意 HTTP verb, 便于按配置分发。行为与
|
|
421
|
+
``get`` / ``post`` / ``put`` / ``patch`` / ``delete`` 一致:
|
|
422
|
+
|
|
423
|
+
- 命中 HTTP 429 时按 ``Retry-After`` / 指数退避自动重试, 最多
|
|
424
|
+
``MAX_RETRIES`` 次;
|
|
425
|
+
- 非 2xx 抛 :class:`qqbotsdk.errors.QQBotAPIError`(OpenAPI 域名下);
|
|
426
|
+
- 返回的响应**未**读取 body, 调用方自己 ``await resp.json()`` 或
|
|
427
|
+
``await resp.read()``, 用完由本方法的上下文管理器释放连接::
|
|
428
|
+
|
|
429
|
+
async with session.request("GET", "/users/@me") as resp:
|
|
430
|
+
data = await resp.json()
|
|
431
|
+
|
|
432
|
+
注意: 直接 ``await session.request(...)`` 拿到的响应不会自动释放,
|
|
433
|
+
与 aiohttp 原生语义一致, 建议一律用 ``async with``.
|
|
434
|
+
"""
|
|
435
|
+
return await self._request_context(method, url, **kwargs)
|
|
420
436
|
|
|
421
437
|
@property
|
|
422
438
|
def closed(self) -> bool:
|
|
@@ -8,13 +8,23 @@
|
|
|
8
8
|
+-- QQBotGatewayError WebSocket 网关层错误
|
|
9
9
|
|
|
10
10
|
调用方 ``except QQBotError`` 可以兜住全部错误, 也可以按层分别处理.
|
|
11
|
+
|
|
12
|
+
业务错误码常量见子模块 :mod:`qqbotsdk.errors.codes`::
|
|
13
|
+
|
|
14
|
+
from qqbotsdk.errors import QQBotAPIError, codes
|
|
15
|
+
|
|
16
|
+
if exc.err_code == codes.MSG_DEDUPLICATED:
|
|
17
|
+
...
|
|
11
18
|
"""
|
|
12
19
|
|
|
20
|
+
from qqbotsdk.errors import codes
|
|
21
|
+
|
|
13
22
|
__all__ = [
|
|
14
23
|
"QQBotAPIError",
|
|
15
24
|
"QQBotAuthError",
|
|
16
25
|
"QQBotError",
|
|
17
26
|
"QQBotGatewayError",
|
|
27
|
+
"codes",
|
|
18
28
|
]
|
|
19
29
|
|
|
20
30
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""OpenAPI 业务错误码常量.
|
|
2
|
+
|
|
3
|
+
``QQBotAPIError.err_code`` 是**业务错误码**, 与 HTTP 状态码分开: HTTP 200 时
|
|
4
|
+
也可能带非零 ``err_code``. 用这里的常量替代魔法数字::
|
|
5
|
+
|
|
6
|
+
from qqbotsdk.errors import QQBotAPIError, codes
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
await ctx.reply("...")
|
|
10
|
+
except QQBotAPIError as exc:
|
|
11
|
+
if exc.err_code == codes.MSG_MSG_ID_EXPIRED:
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
命名规范: 前缀是错误码所属的域(``MSG_`` 消息、``APP_`` 应用权限、
|
|
15
|
+
``FILE_`` 文件), 名字取官方错误表里英文标识的大写形式; 官方只给了中文描述的,
|
|
16
|
+
按描述意译.
|
|
17
|
+
|
|
18
|
+
来源: 官方 [API 调用指南 · 公共错误码] 与各接口页的「错误码」表. 标注为
|
|
19
|
+
「实践观察」的几条未收录在官方公共错误表中, 来自真实 bot 的调用日志, 平台可能
|
|
20
|
+
调整, 不要把它们当成稳定契约.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from typing import Final
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------- 消息收发
|
|
26
|
+
|
|
27
|
+
MSG_DEDUPLICATED: Final = 40054005
|
|
28
|
+
"""相同 msg_id + msg_seq 重复发送被去重. 递增 msg_seq 即可."""
|
|
29
|
+
|
|
30
|
+
MSG_ID_EXPIRED: Final = 40034005
|
|
31
|
+
"""回复消息的 msg_id 已过期, 请在收到消息后尽快回复."""
|
|
32
|
+
|
|
33
|
+
EVENT_ID_INVALID: Final = 40034025
|
|
34
|
+
"""请求参数 event_id 无效或越权."""
|
|
35
|
+
|
|
36
|
+
EVENT_ID_EXPIRED: Final = 40034026
|
|
37
|
+
"""请求参数 event_id 已过期, 请在收到事件后尽快回复."""
|
|
38
|
+
|
|
39
|
+
EVENT_NOT_REPLYABLE: Final = 40034027
|
|
40
|
+
"""该事件不支持回复消息. 例如 GROUP_MEMBER_ADD 只能发主动消息."""
|
|
41
|
+
|
|
42
|
+
MSG_TYPE_MISMATCH: Final = 22006
|
|
43
|
+
"""消息类型与内容不匹配(例如 msg_type=2 却只传了 content)."""
|
|
44
|
+
|
|
45
|
+
MSG_TYPE_INVALID: Final = 340069
|
|
46
|
+
"""消息类型无效, 检查 msg_type 取值."""
|
|
47
|
+
|
|
48
|
+
MSG_CONTENT_INVALID: Final = 304061
|
|
49
|
+
"""消息内容无效, 检查消息格式."""
|
|
50
|
+
|
|
51
|
+
MSG_LENGTH_EXCEEDED: Final = 40054007
|
|
52
|
+
"""消息长度超限."""
|
|
53
|
+
|
|
54
|
+
MSG_URL_NOT_ALLOWED: Final = 40054010
|
|
55
|
+
"""不允许发送 URL."""
|
|
56
|
+
|
|
57
|
+
MSG_PASSIVE_LIMIT: Final = 40034128
|
|
58
|
+
"""被动回复时间或次数超限(群聊 5 次 / 单聊 4 次)."""
|
|
59
|
+
|
|
60
|
+
MSG_ACTIVE_RATE_LIMITED: Final = 40034100
|
|
61
|
+
"""主动消息发送超过频控限制."""
|
|
62
|
+
|
|
63
|
+
BOT_NOT_IN_GROUP: Final = 40054003
|
|
64
|
+
"""机器人不是群成员."""
|
|
65
|
+
|
|
66
|
+
BOT_MUTED: Final = 40054002
|
|
67
|
+
"""机器人被禁言, 等解禁后再发送."""
|
|
68
|
+
|
|
69
|
+
BOT_OFFLINE: Final = 40054016
|
|
70
|
+
"""机器人已下线, 检查网关连接状态."""
|
|
71
|
+
|
|
72
|
+
MEDIA_TRANSFER_FAILED: Final = 40034004
|
|
73
|
+
"""富媒体信息转存失败, 可重试."""
|
|
74
|
+
|
|
75
|
+
FILE_INFO_INVALID: Final = 304080
|
|
76
|
+
"""文件信息无效, 检查 file_info 格式."""
|
|
77
|
+
|
|
78
|
+
MSG_ID_EXPIRED_ALT: Final = 304103
|
|
79
|
+
"""消息 ID 已过期, 不能回复."""
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------- 应用与权限
|
|
82
|
+
|
|
83
|
+
APP_PRIVILEGE_NOT_PASS: Final = 11253
|
|
84
|
+
"""应用权限不通过: 该机器人未获得调用该接口的权限, 需要向平台申请."""
|
|
85
|
+
|
|
86
|
+
APP_PRIVILEGE_CHECK_FAILED: Final = 11252
|
|
87
|
+
"""检查应用权限失败(系统错误), 通常重试一次即可."""
|
|
88
|
+
|
|
89
|
+
APP_INTERFACE_FORBIDDEN: Final = 11254
|
|
90
|
+
"""应用接口被封禁: 有该接口权限但被封禁."""
|
|
91
|
+
|
|
92
|
+
BOT_BANNED: Final = 11265
|
|
93
|
+
"""机器人已经被封禁."""
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------- 实践观察
|
|
96
|
+
# 以下未收录在官方公共错误码表中, 来自真实 bot 的调用日志, 平台可能调整.
|
|
97
|
+
|
|
98
|
+
GROUP_FILE_NO_PERMISSION: Final = 40093005
|
|
99
|
+
"""群文件无权限(实践观察). 常见于机器人缺少群文件读写权限时."""
|
|
100
|
+
|
|
101
|
+
QQ_STREAM_FETCH_FAILED: Final = 40093007
|
|
102
|
+
"""QQ 抓流失败(实践观察). 常见于语音 / 视频链接平台侧拉取失败."""
|
|
103
|
+
|
|
104
|
+
__all__ = [
|
|
105
|
+
"APP_INTERFACE_FORBIDDEN",
|
|
106
|
+
"APP_PRIVILEGE_CHECK_FAILED",
|
|
107
|
+
"APP_PRIVILEGE_NOT_PASS",
|
|
108
|
+
"BOT_BANNED",
|
|
109
|
+
"BOT_MUTED",
|
|
110
|
+
"BOT_NOT_IN_GROUP",
|
|
111
|
+
"BOT_OFFLINE",
|
|
112
|
+
"EVENT_ID_EXPIRED",
|
|
113
|
+
"EVENT_ID_INVALID",
|
|
114
|
+
"EVENT_NOT_REPLYABLE",
|
|
115
|
+
"FILE_INFO_INVALID",
|
|
116
|
+
"GROUP_FILE_NO_PERMISSION",
|
|
117
|
+
"MEDIA_TRANSFER_FAILED",
|
|
118
|
+
"MSG_ACTIVE_RATE_LIMITED",
|
|
119
|
+
"MSG_CONTENT_INVALID",
|
|
120
|
+
"MSG_DEDUPLICATED",
|
|
121
|
+
"MSG_ID_EXPIRED",
|
|
122
|
+
"MSG_ID_EXPIRED_ALT",
|
|
123
|
+
"MSG_LENGTH_EXCEEDED",
|
|
124
|
+
"MSG_PASSIVE_LIMIT",
|
|
125
|
+
"MSG_TYPE_INVALID",
|
|
126
|
+
"MSG_TYPE_MISMATCH",
|
|
127
|
+
"MSG_URL_NOT_ALLOWED",
|
|
128
|
+
"QQ_STREAM_FETCH_FAILED",
|
|
129
|
+
]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from typing import Literal
|
|
1
|
+
from typing import Any, ClassVar, Literal, cast
|
|
2
2
|
|
|
3
|
-
from pydantic import Field
|
|
3
|
+
from pydantic import Field, model_validator
|
|
4
4
|
|
|
5
|
-
from qqbotsdk.model.core import QQBotBaseModel
|
|
5
|
+
from qqbotsdk.model.core import QQBotBaseModel, QQBotRequestModel
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Permission(QQBotBaseModel):
|
|
@@ -76,8 +76,10 @@ class Action(QQBotBaseModel):
|
|
|
76
76
|
class RenderData(QQBotBaseModel):
|
|
77
77
|
label: str | None = Field(
|
|
78
78
|
default=None,
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
description=(
|
|
80
|
+
"按钮文字。平台限制为最多 10 字符,超出部分由平台自行裁剪;"
|
|
81
|
+
"SDK 不在此处校验长度,避免用热词/标题等业务数据时被 ValidationError 卡住"
|
|
82
|
+
),
|
|
81
83
|
)
|
|
82
84
|
visited_label: str | None = Field(
|
|
83
85
|
default=None,
|
|
@@ -207,3 +209,65 @@ class MessageCard(QQBotBaseModel):
|
|
|
207
209
|
default=None,
|
|
208
210
|
description="卡片元素;type=tuwen 时必须包含 title/description/url/pic_url",
|
|
209
211
|
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class MessageSendRequestBase(QQBotRequestModel):
|
|
215
|
+
"""发送消息请求的公共校验: 按内容字段推导 ``msg_type``, 并校验内容互斥.
|
|
216
|
+
|
|
217
|
+
平台的 ``msg_type`` 与内容字段是一一对应的(``content``→0、``markdown``→2、
|
|
218
|
+
``input_notify``→6、``media``→7、``card``→8), 但两个字段都是可选的: 只填
|
|
219
|
+
``markdown`` 而不填 ``msg_type`` 时, 请求体会缺 ``msg_type`` 而只剩内容字段,
|
|
220
|
+
语义全靠平台默认推断. 这里在**校验前**按填入的字段补齐 ``msg_type``, 让
|
|
221
|
+
``SendXxxMessagesRequest(markdown=...)`` 直接就是一个合法的请求.
|
|
222
|
+
|
|
223
|
+
同时把原来只写在 docstring 里的互斥关系变成真校验:
|
|
224
|
+
|
|
225
|
+
- ``markdown`` / ``media`` / ``card`` / ``input_notify`` 四者至多填一个;
|
|
226
|
+
- ``content`` 与 ``markdown`` 互斥(官方: 传了 markdown 后 content 必须为空);
|
|
227
|
+
- ``content`` 可以与 ``media`` 共存, 作为富媒体的附带文本.
|
|
228
|
+
|
|
229
|
+
显式传了 ``msg_type`` 但与内容字段对不上时直接报错, 而不是把矛盾发给服务端.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
# 内容字段 -> 该字段对应的 msg_type
|
|
233
|
+
_MSG_TYPE_BY_FIELD: ClassVar[dict[str, int]] = {
|
|
234
|
+
"markdown": 2,
|
|
235
|
+
"media": 7,
|
|
236
|
+
"card": 8,
|
|
237
|
+
"input_notify": 6,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@model_validator(mode="before")
|
|
241
|
+
@classmethod
|
|
242
|
+
def _infer_msg_type(cls, data: Any) -> Any:
|
|
243
|
+
"""补齐 ``msg_type`` 并校验内容字段互斥."""
|
|
244
|
+
if not isinstance(data, dict):
|
|
245
|
+
return data
|
|
246
|
+
raw = cast("dict[str, Any]", data)
|
|
247
|
+
filled = [name for name in cls._MSG_TYPE_BY_FIELD if raw.get(name) is not None]
|
|
248
|
+
if len(filled) > 1:
|
|
249
|
+
raise ValueError(f"消息内容字段互斥,不能同时传 {filled}")
|
|
250
|
+
has_content = raw.get("content") is not None
|
|
251
|
+
if has_content and "markdown" in filled:
|
|
252
|
+
raise ValueError(
|
|
253
|
+
"content 与 markdown 互斥:传了 markdown 时 content 必须为空"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
if filled:
|
|
257
|
+
inferred = cls._MSG_TYPE_BY_FIELD[filled[0]]
|
|
258
|
+
elif has_content:
|
|
259
|
+
inferred = 0
|
|
260
|
+
else:
|
|
261
|
+
# 没有任何内容字段(例如只带键盘), 保持原样交给平台判断
|
|
262
|
+
return raw
|
|
263
|
+
|
|
264
|
+
declared = raw.get("msg_type")
|
|
265
|
+
if declared is None:
|
|
266
|
+
return {**raw, "msg_type": inferred}
|
|
267
|
+
if declared != inferred:
|
|
268
|
+
source = filled[0] if filled else "content"
|
|
269
|
+
raise ValueError(
|
|
270
|
+
f"msg_type={declared!r} 与内容字段 {source!r} 不匹配,"
|
|
271
|
+
f"按 {source!r} 应为 {inferred}"
|
|
272
|
+
)
|
|
273
|
+
return raw
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"""网关 WebSocket 客户端.
|
|
2
2
|
|
|
3
3
|
对外只需要几个名字: ``Intents``(事件订阅位), ``DEFAULT_INTENTS``(默认订阅),
|
|
4
|
-
``
|
|
5
|
-
``
|
|
4
|
+
``GROUP_BOT_INTENTS``(只做群聊 / 单聊的订阅位), ``GatewayPayload``(事件数据包),
|
|
5
|
+
``ReadyContent``(READY 事件体), ``QQBotWebSocket``(连接客户端),
|
|
6
|
+
``WILDCARD_EVENT``(通配事件名) 与 ``Handler``(回调类型).
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
from qqbotsdk.ws.client import WILDCARD_EVENT, Handler, QQBotWebSocket
|
|
9
|
-
from qqbotsdk.ws.intents import DEFAULT_INTENTS, Intents
|
|
10
|
+
from qqbotsdk.ws.intents import DEFAULT_INTENTS, GROUP_BOT_INTENTS, Intents
|
|
10
11
|
from qqbotsdk.ws.payload import GatewayPayload, OpCode, ReadyContent, ReadyUser
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
13
14
|
"DEFAULT_INTENTS",
|
|
15
|
+
"GROUP_BOT_INTENTS",
|
|
14
16
|
"WILDCARD_EVENT",
|
|
15
17
|
"GatewayPayload",
|
|
16
18
|
"Handler",
|
|
@@ -71,6 +71,26 @@ _FATAL_CLOSE_CODES: Final = frozenset(
|
|
|
71
71
|
{4001, 4002, 4010, 4011, 4012, 4013, 4014, 4914, 4915}
|
|
72
72
|
)
|
|
73
73
|
|
|
74
|
+
# 不可重连关闭码的可读原因, 让报错直接指向怎么修
|
|
75
|
+
_FATAL_CLOSE_REASONS: Final = {
|
|
76
|
+
4001: "无效的 opcode",
|
|
77
|
+
4002: "无效的 payload",
|
|
78
|
+
4010: "无效的 shard",
|
|
79
|
+
4011: "连接数超过限制",
|
|
80
|
+
4012: "无效的 API 版本",
|
|
81
|
+
4013: (
|
|
82
|
+
"无效的 intents:其中有当前应用不可订阅的事件位;"
|
|
83
|
+
"到开放平台确认该 intents 已在「事件订阅」中开通"
|
|
84
|
+
),
|
|
85
|
+
4014: (
|
|
86
|
+
"无权限的 intents:该 intents 未在开放平台开通;"
|
|
87
|
+
"到「开发设置 → 事件订阅」申请对应事件,或改用 "
|
|
88
|
+
"GROUP_BOT_INTENTS 收窄订阅范围"
|
|
89
|
+
),
|
|
90
|
+
4914: "机器人已下架, 请到开放平台检查应用状态",
|
|
91
|
+
4915: "机器人已被封禁",
|
|
92
|
+
}
|
|
93
|
+
|
|
74
94
|
# 其余关闭码(含 4006, 4007, 4900~4913)一律清空会话后重新 Identify
|
|
75
95
|
|
|
76
96
|
|
|
@@ -509,7 +529,11 @@ class QQBotWebSocket:
|
|
|
509
529
|
# 主动关闭, 无需重连
|
|
510
530
|
return
|
|
511
531
|
if code in _FATAL_CLOSE_CODES:
|
|
512
|
-
|
|
532
|
+
reason = _FATAL_CLOSE_REASONS.get(code)
|
|
533
|
+
message = "网关拒绝连接,不可重连"
|
|
534
|
+
if reason is not None:
|
|
535
|
+
message = f"{message}:{reason}"
|
|
536
|
+
error = QQBotGatewayError(message, code=code)
|
|
513
537
|
self._last_error = error
|
|
514
538
|
raise _StopGateway(str(error))
|
|
515
539
|
if code in _RESUMABLE_CLOSE_CODES:
|
|
@@ -42,7 +42,21 @@ DEFAULT_INTENTS: Final = (
|
|
|
42
42
|
| Intents.INTERACTION
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
+
# 只做群聊 / 单聊的机器人用这一组: 不含任何频道域订阅位
|
|
46
|
+
GROUP_BOT_INTENTS: Final = Intents.GROUP_AND_C2C_EVENT | Intents.INTERACTION
|
|
47
|
+
"""群聊 / 单聊机器人的订阅位.
|
|
48
|
+
|
|
49
|
+
``DEFAULT_INTENTS`` 带两个频道位(``GUILD_MEMBERS`` / ``PUBLIC_GUILD_MESSAGES``,
|
|
50
|
+
按官方文档它们属于基础事件、默认有权限, 不会导致连接被拒), 只做群聊的机器人用
|
|
51
|
+
这组更贴合实际订阅范围, 也少一位需要考虑权限的位.
|
|
52
|
+
|
|
53
|
+
注意 ``INTERACTION`` 属于需要申请的特殊事件: 如果机器人不用消息按钮 / 快捷菜单,
|
|
54
|
+
可以进一步收窄成 ``Intents.GROUP_AND_C2C_EVENT``. 订阅了没开通的 intent, 网关会用
|
|
55
|
+
关闭码 4013 / 4014 直接断开.
|
|
56
|
+
"""
|
|
57
|
+
|
|
45
58
|
__all__ = [
|
|
46
59
|
"DEFAULT_INTENTS",
|
|
60
|
+
"GROUP_BOT_INTENTS",
|
|
47
61
|
"Intents",
|
|
48
62
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|