# Pi-Discord

通过 Discord Bot（discord.js Gateway 长连接），将 Discord 作为聊天渠道远程控制 Pi Agent。

在 Discord 中给 Bot 发消息，Pi 自动接收并处理，响应实时回传到 Discord。

## 功能

- 使用 discord.js（Gateway WebSocket 长连接），内置自动重连
- 工具执行进度实时推送：每次工具调用在 Discord 中显示一条可编辑的进度消息
- 中间文本推送：assistant 思考过程中的每一步文本都推送到 Discord，不只是最终回复
- Typing 输入指示：处理中显示打字指示，失败在用户消息上加 ❌
- 媒体收发：图片、文件自动下载/上传，支持双向传递
- Pi LLM 可主动发送文本、图片、文件到 Discord（通过注册的工具）
- 消息去重（轻量，防 Gateway 偶发重投）
- 支持多频道/多用户同时与 Bot 对话
- 支持服务器频道（Guild）和私信（DM）

## 安装

```bash
pi install npm:@xingchen89/pi-discord
```

## 配置

### 创建 Bot 并获取凭证

1. 打开 [Discord Developer Portal](https://discord.com/developers/applications)，创建 Application。
2. 进入 **Bot** 页，点击 **Reset Token** 获取 Bot Token。
3. 在 **Bot** 页开启 **Privileged Gateway Intents → MESSAGE CONTENT INTENT**（必须，否则收到的消息内容为空）。
4. 进入 **OAuth2 → URL Generator**，勾选 `bot` scope 与所需权限（至少 `Send Messages`、`Read Message History`、`Add Reactions`、`Attach Files`、`Create Public Threads`、`Send Messages in Threads`），用生成的链接把 Bot 邀请进你的服务器。

### 配置方式

支持三种配置方式，优先级从高到低：

**1. CLI 标志**

```bash
pi --discord-token=xxx
```

**2. 环境变量**

```bash
export DISCORD_BOT_TOKEN="xxx"
```

**3. Pi settings.json（推荐）**

在 `.pi/settings.json`（项目级）或 `~/.pi/agent/settings.json`（全局）中添加：

```json
{
  "discord": {
    "token": "xxx",
    "appId": "",
    "requireMention": true,
    "mentionPatterns": [],
    "useThread": true
  }
}
```

字段名支持 camelCase（`appId`）和 snake_case（`app_id`）两种写法。项目级配置覆盖全局配置。

### 配置项说明

| 字段 | 环境变量 | CLI 标志 | 必需 | 默认 |
|------|----------|----------|------|------|
| Bot Token | `DISCORD_BOT_TOKEN` | `--discord-token` | 是 | — |
| App ID | `DISCORD_APP_ID` | `--discord-app-id` | 否 | — |
| 频道需 @机器人 | `DISCORD_REQUIRE_MENTION` | — | 否 | `true` |
| 触发正则 | — | — | 否 | 空 |
| 进度放入 thread | `DISCORD_USE_THREAD` | — | 否 | `true` |

## 触发方式（重要）

为避免在服务器频道里对**每一条消息**都响应，Bot 的触发规则为：

- **私信（DM）**：始终响应，无需 @机器人。
- **服务器频道（Guild）**：默认**只在被触发时**响应。以下任一情况算被触发：
  1. 消息中 **@机器人**；
  2. **回复（reply）**机器人发出的某条消息；
  3. 命中 `mentionPatterns` 中任一正则（如 `["^pi[\\s,:]"]` 让以 `pi ` 开头的消息也能触发）。

若某个频道由机器人独占、希望它响应所有消息，把 `requireMention` 设为 `false`（或 `DISCORD_REQUIRE_MENTION=false`）。此项不影响 DM。

## 工具进度与 Thread

当一次回答涉及工具调用时，Bot 会在服务器频道里**针对该条用户消息开一个 thread**，把工具进度卡片（⏳→✅/❌，原地编辑更新）放进 thread，主频道只保留干净的「问题 + 中间文本 + 最终回复」。

- 仅在**首次出现工具调用时**才创建 thread，纯文本问答不会生成空 thread。
- thread 名取用户消息前 80 字，60 分钟无活动自动归档。
- 以下情况自动**回退**到「频道内直接发进度卡片」：DM（私信没有 thread）、消息本身已在某个 thread 内、频道类型不支持、或缺少建 thread 权限。
- 不想用 thread：把 `useThread` 设为 `false`（或 `DISCORD_USE_THREAD=false`）。

### 启动

```bash
pi
```

Pi 启动时会自动加载 pi-discord 扩展并连接 Discord Gateway。在 Discord 中给 Bot 发消息（或在服务器频道 @Bot）即可开始使用。

## 管理命令

在 Pi 终端中使用 `/discord` 命令管理连接：

| 命令 | 说明 |
|------|------|
| `/discord start` | 启动 Discord Bot 连接 |
| `/discord stop` | 断开连接 |
| `/discord status` | 查看连接状态 |
| `/discord config` | 查看当前配置 |
| `/discord help` | 显示帮助 |

在 Discord 聊天中可用的斜杠命令（由扩展直接处理，不发给 LLM）：

| 命令 | 说明 |
|------|------|
| `/new` | 新建会话（重置上下文） |
| `/stop` | 中断当前处理，清空排队 |
| `/queue` | 查看排队状态 |
| `/compact` | 压缩上下文 |
| `/status` | 查看 Pi 状态 |
| `/help` | 显示帮助 |

## 事件映射

| Pi 事件 | Discord 动作 |
|---------|----------|
| 入站消息 | 显示 Typing + 转发给 Pi |
| `tool_execution_start` | 在 thread 内创建/更新进度消息（见「工具进度与 Thread」） |
| `tool_execution_end` | 更新进度消息（标记完成/失败） |
| `turn_end`（含工具调用） | 发送中间文本（回复模式） |
| `turn_end`（纯文本） | 发送最终回复（新消息） |
| `agent_end` | 停止 Typing |

## 注册的 Pi 工具

Pi LLM 可以主动调用以下工具向 Discord 发送内容：

| 工具名 | 说明 |
|--------|------|
| `send_to_discord` | 发送文本消息到 Discord |
| `send_image_to_discord` | 上传并发送图片到 Discord |
| `send_file_to_discord` | 上传并发送文件到 Discord |

## 架构

```
+---------------------+   Gateway (discord.js)   +--------------------+
|   Discord 网关       | <----------------------> |  Pi Extension      |
|   discord.com       |       messageCreate      |  (discord-client)  |
+---------------------+                          +---------+----------+
                                                           |
                                                           | sendUserMessage()
                                                           | on("turn_end")
                                                           | on("tool_execution_*")
                                                           v
                                                  +--------------------+
                                                  |  Pi Agent Core     |
                                                  |  (LLM + Tools)     |
                                                  +--------------------+
```

## 项目结构

```
pi-discord/
+-- src/
|   +-- index.ts           # Pi 扩展主入口，事件处理，工具注册
|   +-- discord-client.ts  # Discord Gateway 客户端封装
|   +-- types.ts           # 类型定义
+-- package.json
+-- README.md
```

## 开发

```bash
npm install
npm run typecheck
pi -e ./src/index.ts --discord-token=YOUR_TOKEN
```

## 注意事项

1. Bot Token 请妥善保管，不要提交到版本控制
2. 必须在 Developer Portal 开启 **MESSAGE CONTENT INTENT**，否则消息内容为空
3. 单条消息最大 2000 字符（Discord 限制），长消息自动分块
4. 媒体文件下载到系统临时目录（`/tmp/discord-media/`）
5. 收私信（DM）需要 Bot 与用户有共同服务器或用户主动发起 DM

## License

MIT
