@ 聊天适应器/ x
npm 软件包 :
@chat-adapter/x
X (twitter) 适配器,用于 聊天SDK,使用 X API v2 (英语) 编辑 X 活动 API答复公众提及,举行管理部对话,张贴博特账户,以及类似张贴.
联合国 聊天-sdk.dev/适应者/正式/x 指南: vercel.com/kb/chat-sdk (英语)
安装
pnpm add @chat-adapter/x
带CLI的脚手架
要用这个适配器预选的新X机器人脚手架:
npx create-chat-sdk@latest my-bot --adapter x memory
访问 适配器目录 见其他官方和供应商官方适配器.
使用量
import { Chat } from "chat";
import { createXAdapter } from "@chat-adapter/x";
const bot = new Chat({
userName: "mybot",
adapters: {
x: createXAdapter(),
},
});
bot.onNewMention(async (thread, message) => {
await thread.post(`Hi @${message.author.userName}!`);
});
bot.onDirectMessage(async (thread, message) => {
await thread.post("Hello from X!");
});
使用时 createXAdapter() 证书由环境变量自动检测.
X 设置
1. 创建 X 应用程序
- 转到 X 开发者门户网站 并创建工程和 App
- 下 键和符号,复制 API 密钥 这变成了
X_CONSUMER_SECRET - 启用 OAuth 2.0 数据 带有范围的用户认证
tweet.read, (中文(简体) ),tweet.write, (中文(简体) ),users.read, (中文(简体) ),dm.read, (中文(简体) ),dm.write, (中文(简体) ),like.write,以及offline.access - 完成 Bot 账户的 OAuth 2.0 流量 。 将访问符作为
X_USER_ACCESS_TOKEN,或存储X_CLIENT_ID加号X_REFRESH_TOKEN让适配器管理令牌刷新
2. 登记网点
X通过 X 活动 API设置它一次在 X 开发者控制台,它为您处理认证:
- 注册您的 Webhook URL(
https://your-domain.com/api/webhooks/x) (中文(简体) ). 它必须是没有港口的公共HTTPS. X 立即发出 CRC 挑战,适配器自动回答 - 为适配器占用的事件创建订阅 :
post.mention.create, (中文(简体) ),dm.received,以及dm.sent(私人活动,所以机器人用户必须先授权您的应用)
订阅和webhook管理是一次性设置,而不是适配器运行时间. 如果您不使用控制台来脚本它,活动 API 端点是认证选择并针对操作的,并且不完全匹配已发布的 spec(在测试中创建一个需要的私事订阅 OAuth 1.0a 用户上下文,同时列出和删除只使用应用程序无记名符号),所以控制台是比较简单的路径.
3. 环境变量
X_CONSUMER_SECRET=... # App API key secret, used for webhook CRC and signature verification
# Auth option A: static access token
X_USER_ACCESS_TOKEN=... # OAuth 2.0 user-context access token for outbound calls
# Auth option B: managed OAuth refresh (recommended for long-running bots)
X_CLIENT_ID=... # OAuth 2.0 client ID
X_REFRESH_TOKEN=... # OAuth 2.0 refresh token (requires the offline.access scope)
X_CLIENT_SECRET=... # Optional, only for confidential clients
X_ENCRYPTION_KEY=... # Optional, base64 32-byte key to encrypt persisted tokens
X_USER_ID=... # Bot account user ID. Optional if omitted it is fetched from /2/users/me; the adapter requires a resolvable bot id and fails init otherwise
X_USERNAME=... # Optional, bot @handle for mention detection (fetched when omitted)
X_API_BASE_URL=... # Optional, override the X API base URL
托肯刷新
X OAuth 2.0用户代号为短寿命(约2小时). 与 X_CLIENT_ID 财务报告和审定财务报表 X_REFRESH_TOKEN 设置,适配器在到期前刷新访问令牌,并在您的状态适配器中坚持旋转的刷新令牌,因此机器人能够活下来重启。 设定 X_ENCRYPTION_KEY 以存储加密的 AES-256-GCM 令牌.
或者,通过一个符号提供者并插入您自己的刷新逻辑 :
import { createXAdapter } from "@chat-adapter/x";
const adapter = createXAdapter({
userAccessToken: async () => refreshTokenFromMyStore(),
});
Webhook 设置
X使用两种由适配器处理的webhook机制:
- 《儿童权利公约》的挑战 X发送一个
crc_token适配器用HMAC -SHA256响应 以您的消费者秘密为键 X 重新验证小时数 - 事件交付 活动活动:
x-twitter-webhooks-signature标题, 对照原始请求体进行校验
// Next.js App Router example
import { bot } from "@/lib/bot";
export async function GET(request: Request) {
return bot.webhooks.x(request);
}
export async function POST(request: Request) {
return bot.webhooks.x(request);
}
特征
通讯
| 特性 | 支助 |
|---|---|
| 邮件 | 有(提醒答复和模式草案) |
| 高级员额 | 对(channel.post 打开 x:public(中文(简体) ) |
| 编辑信件 | 只有职位(适用X编辑资格规则) |
| 删除信件 | 员额和自己的管理部活动 |
| 流线 | 缓冲(累计一次员额) |
| 打字指标 | 没有 |
丰富内容
| 特性 | 支助 |
|---|---|
| 卡片格式 | 纯文本倒置 |
| 按钮 | 否( 链接按钮渲染为文本) |
| 表格 | ASC 二届理事会 |
| 模块 | 没有 |
| 图像上传 | 是(png、jpeg、webp;每个员额最多4个;以及模式草案) |
通过粘接图像 files (或 attachments)在消息上;适配器通过X块媒体端点上传每个端点(initialize 接下来 append 接下来 finalize并附上返回者 media_id职位或管理部。 一个帖子可以携带有或没有文字的媒体.
await thread.post({
markdown: "France lead the title race",
files: [{ data: pngBuffer, filename: "odds.png", mimeType: "image/png" }],
});
媒体上传需要 media.write 在 OAuth 2.0 令牌上显示 tweet.write。用 media.write 用 403 包含或上传失败 .
对话
| 特性 | 支助 |
|---|---|
| 提及 | 对(post.mention.create(中文(简体) ) |
| 模式 | 对(dm.received 编号 : dm.sent(中文(简体) ) |
| 反应 | 只喜欢emoji.heart 或者说 "like"(中文(简体) ) |
| 用户查询 | 对 |
信件历史
| 特性 | 支助 |
|---|---|
| 获取信件 | 通过 API 的 DMs , 缓存的帖子 |
| 获取单个消息 | 通过API、DM从缓存中的员额 |
线索标识格式
x:post:{conversationId} # public post threads (channel: x:public)
x:dm:{participantUserId} # direct message with a single user
实例: x:post:1943467279943467279, (中文(简体) ), x:dm:783214X DM Webhooks不携带对话id,只有参与者ids,因此DMs被另一个参与者的用户id所线程: openDM("783214") 返回时 x:dm:783214,并发送路径到 POST /2/dm_conversations/with/783214/messages顶级职位通过 channel.post 编辑 x:public 频道.
自动化政策
X 执行 自动化规则。在部署机器人之前:
- 在发送自动答复或模式草案之前获得明确同意,并立即履行退出义务
- 在账户配置中披露机器人身份
- 从不发送批量、复制或主动的自动化内容
- 只使用正式的 API( 不刮取或浏览器自动化)
适配器默认是严格的:它从不流出后编辑,大声拒绝不支持的交互,只有在您的处理者决定时才回答.
XChat( 加密信件)
XChat是X的加密消息产品. 它从船上飞来 @chat-adapter/x/chat
此软件包的子路径, 因此它安装在 @chat-adapter/x 添加无
依赖性, 除非你导入它 .
import { createXchatAdapter } from "@chat-adapter/x/chat";
XChat 密码堆栈(@xdevplatform/chat-xdk, (中文(简体) ), @xdevplatform/xdk, (中文(简体) ),
juicebox-sdk)被宣布为可选的对等依赖。 安装它们
并行 @chat-adapter/x 当你使用这个子路径.
使用量
import { Chat } from "chat";
import { createXchatAdapter } from "@chat-adapter/x/chat";
import { createMemoryState } from "@chat-adapter/state-memory";
const bot = new Chat({
userName: "mybot",
adapters: {
xchat: createXchatAdapter(),
},
state: createMemoryState(),
});
// DMs always
bot.onDirectMessage(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});
// Group chats when the bot is @mentioned
bot.onNewMention(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});
接通网路(如. app/api/webhooks/xchat/route.ts 在下一个.js中:
import { bot } from "@/lib/bot";
export async function GET(request: Request) {
return bot.webhooks.xchat(request);
}
export async function POST(request: Request) {
return bot.webhooks.xchat(request);
}
使用时 createXchatAdapter() 证书由环境变量自动检测。 机器人的 @ handle 解决自 GET /2/users/me 在启动时,请提及检测工作,而没有任何硬编码.
XChat 设置
1. 注册加密密钥
机器人账户需要注册的公用钥匙和一个Juicebox后置的私人钥匙商店,然后才能参与加密的对话:
- 生成密钥pairs with
chat-xdk(单位:千美元)generateKeypairs()(中文(简体) ) - 通过
POST /2/users/{id}/public_keys - 在 Juicebox 中用 PIN 存储私钥(
chat.setup(pin)(中文(简体) )
适配器在启动时用相同的 PIN 解锁密钥(XCHAT_PIN) (中文(简体) ). 登记是每个账户的一次性步骤——见 聊天- xdk 文档 为了整个流动.
2. 创建网点
注册一个webhook URL,使 X 活动 API 能够传送事件(文档:
curl -X POST "https://api.x.com/2/webhooks" \
-H "Authorization: Bearer $APP_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-domain.com/api/webhooks/xchat"}'
X 用 CRC 挑战验证 URL (参见 Webhook 路线 ),所以终点必须在创建"网络呼克"之前进行直播.
也可以创建和管理 Webhooks 和活动订阅 X 开发者门户 而不是通过API.
3. 订阅聊天活动
创建 活动订阅 用于装有 bot 的 OAuth2 用户代号的机器人用户 :
curl -X POST "https://api.x.com/2/activity/subscriptions" \
-H "Authorization: Bearer $BOT_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event_type": "chat.received",
"filter": {"user_id": "YOUR_BOT_USER_ID"},
"tag": "bot-chat-received",
"webhook_id": "YOUR_WEBHOOK_ID"
}'
订阅 chat.conversation_join 如果你希望机器人在加入一个组时发出一个欢迎信息.
Webhook 路线
X发出两种请求:
- 《儿童权利公约》的挑战 (GET) - (英语)
?crc_token=...以HMAC -SHA256的代号 以你的应用软件的消费者秘密为键 适配器回答这个,所以路线也去. - 事件交付 (POST)——聊天活动,由适配器通过
x-twitter-webhooks-signature头曰.
import { bot } from "@/lib/bot";
export async function GET(request: Request) {
return bot.webhooks.xchat(request);
}
export async function POST(request: Request) {
return bot.webhooks.xchat(request);
}
不要在您的操作器上签名 。 挑战与 POST 签名使用相同的密钥,算法,以及 sha256= 前缀,所以一个处理器可以使 HMAC 任意 crc_token 成为签名预告器:一个呼叫者可以通过一个被伪造的事件体作为符号,并将响应重放为 x-twitter-webhooks-signature如上所示,路径通过适配器;在签名前拒绝错误的CRC标志.
配置
在不提供时,所有选项都从环境变量中自动检测出.
| 选项 | 需求 | 说明 |
|---|---|---|
botToken 编号 : accessToken | 无* | OAuth2 机器人账户用户访问令牌. 自动从 XCHAT_BOT_TOKEN 或者说 X_ACCESS_TOKEN |
pin | 没有 | Juicebox PIN; 设定时, 密钥会自动解锁 initialize()自动从 XCHAT_PIN |
consumerSecret | 为网友 | 应用消费者秘密来验证Webhook签名. 自动从 X_CONSUMER_SECRET。 。 。 . 需要接收网点: X 在每个 POST 上签名,所以没有它,每个 POST 会被以 401 拒绝. 投票部署不需要 |
disableWebhookVerification | 没有 | 在不验证其HMAC的情况下接受 Webhook POST. 自动从 X_DISABLE_WEBHOOK_VERIFICATION。只有在上游层验证签名时才使用。 未推荐生产 |
editSafetyDelayMs | 没有 | 新发布消息的最小年龄(ms)必须在发送第一次编辑前到达,所以接收客户端已经存储了原始编辑目标. 默认为 5000· ; 0 禁用等号 |
sendReadReceipts | 没有 | 在处理器运行前发送每个发送的输入信件的读取收据( 默认) true(中文(简体) ) |
userName | 没有 | 瓶子 @ handle 用于检测 。 自动从 X_BOT_USERNAME,以其他方式解决 GET /2/users/me |
welcomeMessage | 没有 | 当机器人加入一个组时发布消息 . false 禁用; 省略使用默认解释@mention- to-reply |
verifySignatures | 没有 | 要求在收到的信件上签名( 默认) true) (中文(简体) ). X_VERIFY_SIGNATURES=false 选择退出 |
signingKeyVersion | 没有 | 签名密钥版本覆盖 。 通常在 initialize()自动从 X_SIGNING_KEY_VERSION |
apiBaseUrl | 没有 | 媒体 REST 调用的基准 URL( 默认为 https://api.x.com(中文(简体) ) |
apiHeaders | 没有 | 在每个 X API 请求上都添加了信头 。 除非它包括一个 User-Agent,适配器预置 chat-sdk-xchat/<version> 到客户端的默认值,所以聊天SDK流量可以识别 |
logger | 没有 | 锁定实例( 默认为 ConsoleLogger("info")(中文(简体) ) |
* 运行时需要——通过配置或环境变量.
环境变量
XCHAT_BOT_TOKEN=xcbot_... # OAuth2 user token for the bot account
XCHAT_PIN=... # Juicebox PIN for key unlock
X_CONSUMER_SECRET=... # App secret (CRC + webhook signature verification)
X_BOT_USERNAME=... # Optional @handle override; resolved from /2/users/me otherwise
X_VERIFY_SIGNATURES=true # Optional; set false to accept unverifiable messages
特征
通讯
| 特性 | 支助 |
|---|---|
| 邮件 | 是( 加密 + 签名) |
| 集体答复 | 是(对触发消息的引用答复) |
| 编辑信件 | 是(加密了针对原始序列 ID 的编辑事件;只有机器人自己的短信). 首个新消息的编辑会持续到消息 editSafetyDelayMs 旧的,所以接收客户端在编辑到来之前就存储了原件 |
| 删除信件 | 是( 全部删除: 本地签名的删除动作会删除每个参与者的信件; 只有机器人自己的信件) |
| 流线 | 有限(消息编辑工作,但第一次编辑时间为 editSafetyDelayMs快速的逐个更新是粗糙的) |
| 读取收据 | 是(通过发送的每封送入信件,使对话提前读取水印,除非 sendReadReceipts: false; 调用 thread.markAsRead() 手动控制) |
| TTL 传播 | 是( 复制人继承输入信件的消失消息- TTL) |
丰富内容
| 特性 | 支助 |
|---|---|
| 标记 | 没有客户端渲染 — 向外的标记下字面显示为纯文本(表格为例外,见下文) |
| URL / @mention 实体 | 是(在外出文本中被检测出,作为可挖掘链接和提及药丸提供) |
| 邮政卡 | 是(第一个) x.com/.../status/... 正在发送的文本自动附件中的 URL) |
| 媒体出去 | 是(文件加密流并经由三步媒体上传流程上传) |
| 媒体 | 是(通过懒惰下载披露的附件+解密) fetchData()(中文(简体) ) |
| 卡片/ 按钮/ 模式 | 否( XChat 没有交互式信件表面) |
| 表格 | ASCII 代码块 |
对话
| 特性 | 支助 |
|---|---|
| 提及 | 是 (结构上提及实体, 刷新到机器人, 纯文本) @handle 倒计时) |
| 添加/ 删除反应 | 对 |
| 即将出现的反应 | 是(按程序进行) onReaction(中文(简体) ) |
| 打字指标 | 是(在操作员运行时,每3次保留一次) |
| 模式 | 对 |
| 分组聊天 | 对(g-前置对话ID) |
| 集团加入欢迎 | 是( 可通过 welcomeMessage(中文(简体) ) |
| 打开管理部 | 对(openDM(userId) 重用已有的对讲机或运行新密钥交换机; 要求收件人设置加密聊天器) |
信件历史
| 特性 | 支助 |
|---|---|
| 获取信件 | 对(GET /2/chat/conversations/{id}/events,批次解密) |
| 获取线索信息 | 对 |
| 列表线索 | 没有 |
在团体中提及行为
chat.onNewMention(handler) 给提到机器人的团体信息起火。 当 :
- 内容丰富 提及实体 包括机器人的@handle或用户ID——权威信号,或
- 这是一个 刷新复制 给机器人的一条信息,或者
- 它的纯文本包含
@handle(当没有实体存在时倒计时).
对没有提及机器人的群组信息,请登记 chat.onNewMessage(handler) 没有规律.
线索标识格式
xchat:{conversationId}
- 1:1 个对话 :
xchat:1234567890-9876543210(均为参与者身份) - 分组对话 :
xchat:g123456789(不公开)g- 前置标识)
REST 路径使用另一个参与者的用户ID进行 1:1 个对讲和 g... 组的ID;适配器自动转换.
加密注释
- 对话键通过
KeyChange事件并被缓存到每个谈话和密钥版本。 当一个密钥在发送时间丢失时,适配器会获取最近的对话事件取出一个. - 以参与者的签名密钥(取自
GET /2/users/{id}/public_keys和缓存)。 与verifySignatures: true(默认),不可验证信件被删除. - 媒体使用流传加密与消息文本分开加密;消息带有
media_hash_key用于下载和解密blob.
解决问题
CRC 验证失败
- 确认
X_CONSUMER_SECRET匹配您的应用程序在开发者门户网站上的消费者秘密 - 对策必须是
{"response_token": "sha256=<base64 HMAC>"}获取请求
未抵达的事件
- 校验订阅存在 :
GET /2/activity/subscriptions与应用程序无记名标志 - 确认订阅
webhook_id在網址上标出您的活端点 - 订阅更改需要几分钟才能提供
在 Webhook POSTs 上的"无效签名"
- 适配器验证
x-twitter-webhooks-signature由 HMAC-SHA256 键入X_CONSUMER_SECRET确定是同一个软件拥有网页
信件解密, 但机器人从未在组中回复
- 组回复需要提及 —— 请检查发送者是否真的提及了机器人的手柄( 来自
/2/users/me),或使用{ allGroupMessages: true }
张贴时没有对话键
- 机器人只能发送到对话中与它共享一个对话密钥(即有人先给机器人发信息,将其添加到组中,或者机器人自己打开对话通过)
openDM(userId)) (中文(简体) ).openDM要求接收者设置加密聊天,服务器则要求接收者在接受第一个消息之前信任bot(例如跟随它).
AI 编码代理
如果您使用OpenAI Codex, Claude Code, 或 Cursor 等AI编码代理, 在写入代码前安装 Chat SDK 技能, 使其了解 SDK API, 适配器模式, 以及项目常规 .
npx skills add vercel/chat
技术参考文献 node_modules/chat/docs,加上已发布的软件包中的适配器指南和启动模板.
您也可以安装 Vercel 插件 包括Chat SDK技术与专家代理、代理斜线命令以及更多:
npx plugins add vercel/vercel-plugin
插件是可选的;单是技能就足以用Chat SDK来构建.
关于可代理阅读的文件,见 聊天- sdk.dev/llms.txt (页数索引)或 聊天- sdk.dev/llms- full.txt (全文).
许可证
麻省理工学院