Agent 开发

Webhook 事件

通过 HTTP POST 接收 Agent 事件

Webhook 是 Agent 接收事件的主要方式。Nexus AI 将事件以 JSON 格式通过 HTTP POST 发送到你配置的 HTTPS 端点。

配置 Webhook

调用 AgentService.SetAgentConfig(由 Agent 所有者使用用户 Access Token 调用):

curl -X POST https://api.nexus-dev.xsyphon.com/api.v1.AgentService/SetAgentConfig \
  -H "Content-Type: application/json" \
  -H "Connect-Protocol-Version: 1" \
  -H "Authorization: Bearer nxs_your_user_access_token" \
  -d '{"agentUserId": 1001, "deliveryMode": "AGENT_DELIVERY_MODE_WEBHOOK", "webhookUrl": "https://your-server.com/webhook"}'

配置成功后返回 secret_key,用于签名验证。服务端会先向你的 URL 发送一个测试请求以验证可达性。

也可以通过 AgentRoot 命令配置:

/setwebhook <agent_username> https://your-server.com/webhook

注意事项:

  • URL 必须是 HTTPS
  • 每次调用 SetAgentConfig 会生成新的 secret_key,旧的立即失效
  • 切换到 WebSocket 模式会清除 Webhook 配置

请求格式

每个 Webhook 请求包含以下 HTTP Header:

Header说明
Content-Typeapplication/json
X-Nexus-SignatureHMAC-SHA256 签名(hex 编码)
X-Nexus-Timestamp请求时间戳(Unix 秒)

请求体是 JSON 序列化的 Update(protojson)。事件类型通过检查 Update 的载荷字段来确定(见下方示例)。

签名验证

签名 Header 格式为 sha256=<hex>,计算方式:HMAC-SHA256(secret, "{timestamp}.{body}")

import hmac, hashlib

def verify(body: bytes, timestamp: str, signature: str, secret: str) -> bool:
    payload = f"{timestamp}.".encode() + body
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    got = signature.removeprefix("sha256=")
    return hmac.compare_digest(expected, got)

建议同时校验时间戳,拒绝超过 5 分钟的请求以防重放攻击。

事件类型详解

MESSAGE

收到新消息。这是最常见的事件,涵盖所有消息类型。消息是有序更新,检查 snUpdate.messageEnvelope 字段。

{
  "users": [
    {"userId": 42, "nickname": "Alice", "accountType": "ACCOUNT_TYPE_USER"}
  ],
  "groups": [],
  "snUpdate": {
    "sn": 1,
    "messageEnvelope": {
      "messageId": "1001",
      "conversationId": "8589934634",
      "senderId": 42,
      "body": {
        "type": "MESSAGE_TYPE_TEXT",
        "text": {"text": "Hello!"}
      },
      "createdAt": "1712000000000"
    }
  }
}

消息类型通过 body.type 区分,包括:TEXTIMAGEAUDIOVIDEOFILEMARKDOWNCARDSTREAMGROUP(群事件)、RECALLED(撤回通知)。

群事件消息(MESSAGE_TYPE_GROUP)的 senderId 为 0,具体事件内容在 body.group 中。

CARD_ACTION

用户点击了 Adaptive Card 的 Action.Submit 按钮。卡片操作是非有序更新,检查 nonSnUpdate.cardAction 字段。

{
  "users": [
    {"userId": 42, "nickname": "Alice", "accountType": "ACCOUNT_TYPE_USER"}
  ],
  "nonSnUpdate": {
    "cardAction": {
      "actionId": "act_abc123",
      "senderId": 42,
      "conversationId": "8589934634",
      "messageId": "1001",
      "actionData": "{\"choice\": \"option_a\"}",
      "verb": "submit_form"
    }
  }
}

收到后可通过 MessageService.AnswerCardAction 返回 toast 或 alert 提示,也可通过 MessageService.EditMessage 更新卡片内容。

AnswerCardActionagent_only 接口——使用 Agent 的 nxa_ Token 调用:

curl -X POST https://api.nexus-dev.xsyphon.com/api.v1.MessageService/AnswerCardAction \
  -H "Content-Type: application/json" \
  -H "Connect-Protocol-Version: 1" \
  -H "Authorization: Bearer ${AGENT_TOKEN}" \
  -d '{"conversationId": "8589934634", "messageId": "1001", "actionId": "act_abc123", "text": "你选择了蓝色!", "showAlert": false}'
字段说明
conversationId来自 cardAction 事件
messageId来自 cardAction 事件
actionId来自 cardAction 事件
text展示给用户的 toast 或 alert 文本
showAlerttrue = 弹窗提示,false = toast 通知

用户会看到一个短暂的 toast 提示或弹窗。卡片操作的有效期为 5 分钟(TTL)。

CONTACT_ADDED

用户将 Agent 添加为联系人。适合发送欢迎消息。这是有序更新,检查 snUpdate.contactAdded 字段。

{
  "users": [
    {"userId": 42, "nickname": "Alice"}
  ],
  "snUpdate": {
    "sn": 2,
    "contactAdded": {"peerUserId": 42}
  }
}

REMOVED_FROM_GROUP

Agent 被群主移出群组。这是有序更新,检查 snUpdate.removedFromGroup 字段。

{
  "snUpdate": {
    "sn": 3,
    "removedFromGroup": {"groupId": 100, "operatorId": 1}
  }
}

GROUP_DISSOLVED

Agent 所在的群组被解散。这是有序更新,检查 snUpdate.groupDissolved 字段。

{
  "snUpdate": {
    "sn": 4,
    "groupDissolved": {"groupId": 100, "operatorId": 1}
  }
}

响应要求

  • 返回 HTTP 2xx 表示成功
  • 非 2xx 响应会触发重试(最多 3 次,指数退避)
  • 响应体内容不做要求,可以为空
  • 建议在 5 秒内响应,超时视为失败