# Pi Bot

这是一个基于 `pi-mono` / `@mariozechner/pi-coding-agent` 的 Bot 项目。

## 当前结构

- `bin/pi-bot.ts`
  - CLI 入口，通过 `pnpm link --global` 注册为全局命令 `pi-bot`
- `src/cli.ts`
  - CLI 命令实现（`config set/get/list/delete`）
- `src/config.ts`
  - 项目唯一配置入口，读取 `config.json` 并装配 `BotAppConfig`
- `src/index.ts`
  - 应用启动入口
- `src/agent.ts`
  - agent runtime 封装
- `src/pi-resources.ts`
  - repo 内置 Pi 资源装配，统一把源码目录接到 runtime
- `pi-resources/`
  - 版本管理下的 skills / prompts / extensions / SYSTEM.md 源码目录
- `src/dashboard/config-store.ts`
  - Dashboard 配置读写抽象，支持文件和内存两种存储
- `src/core.ts`
  - 通用消息协议、共享类型和 helper
- `src/channels/feishu`
  - 飞书 channel
- `src/channels/wechat`
  - 微信 channel
- `tests/smoke`
  - 基础 smoke test（使用内存配置存储验证 dashboard 配置读写链路）
- `tests/config.test.ts`
  - config 解析与模型构建测试
- `tests/cli.test.ts`
  - CLI config 命令测试
- `types`
  - 本地类型声明补充
- `docs/project-overview.md`
  - 项目结构与实现介绍
- `docs/user/getting-started.md`
  - 用户快速开始文档，Dashboard 的 `Docs` 页面会直接展示这份 Markdown

## Start

```bash
npm install
npm run dev
```

`npm run dev` 会先按顺序加载 `.env` 和 `.env.local`，然后启动 `src/index.ts`。
默认会使用 `pi` runtime；如果你只是想走本地 mock 链路，可以额外设置 `PI_BOT_AGENT_MODE=mock`。

如果默认的 `<%= workspaceDir %>/config.json` 不存在，启动时会输出 warning，并自动回退到最小 mock 配置；此时默认会以 `mock` runtime 运行。

## 用户文档

启动后，可以在 Dashboard 的 `Docs` 页面查看当前项目的用户指引，默认地址是：

```txt
http://127.0.0.1:5000/docs
```

用户文档的 Markdown 源文件位于 `docs/user/getting-started.md`。如果你修改了接入步骤或调整了用户可见行为，请同步更新这份文档。

## 常用命令

```bash
npm run dev
npm run build
npm test
npm run smoke
npm run typecheck
```

## CLI

项目提供 `pi-bot` 命令行工具，用于通过终端直接读写 `workspace/config.json`。

### 安装

首次使用前需要全局注册（`scripts/prepare.sh` 会自动检测并执行）：

```bash
pnpm link --global
```

### 用法

```bash
# 设置配置项（支持嵌套路径，值会自动推导类型）
pi-bot config set channels.feishu.appId cli_xxxxx
pi-bot config set channels.feishu.enabled true
pi-bot config set models.providers.coze.models.0.maxTokens 16384

# 读取配置项
pi-bot config get channels.feishu.appId
pi-bot config get channels.feishu

# 查看完整配置
pi-bot config list

# 删除配置项
pi-bot config delete channels.feishu.thinkingReaction.emojiType
```

值类型推导规则：
- `true` / `false` → boolean
- 纯数字 → number
- `null` → null
- 其他 → string

## Agent 模式

- 默认情况下，`npm run dev` 使用 `PI_BOT_AGENT_MODE=pi`
- `PI_BOT_AGENT_MODE=mock`
  - 使用 mock runtime，适合本地链路验证
- `PI_BOT_AGENT_MODE=pi`
  - 使用真实 `pi-coding-agent` runtime

除 `PI_BOT_AGENT_MODE` 和飞书相关环境变量外，agent 的模型、provider、workspace、thinking level 都从 `<%= workspaceDir %>/config.json` 读取。

## Provider 配置

provider 不再通过项目内的特化实现硬编码，而是从 `<%= workspaceDir %>/config.json` 的 `models.providers` 读取。

如果你已经启动了本地 Dashboard，现在也可以直接在界面里切换默认模型：

- `http://127.0.0.1:5000/models`
  - 选择默认模型（选择后会自动保存）

默认情况下，Dashboard 会通过文件型 `ConfigStore` 读写 `<%= workspaceDir %>/config.json`，保存后需要重启进程让配置生效。测试或嵌入场景也可以通过 `createBotApp(..., { dashboardConfigStore })` 注入内存型 `ConfigStore`，避免依赖真实配置文件。

## Pi 资源

项目内置的 Pi 资源统一维护在 `pi-resources/` 下，并在 runtime 初始化时以代码方式注入：

- `pi-resources/extensions/`
- `pi-resources/skills/`
- `pi-resources/prompts/`
- `pi-resources/SYSTEM.md`

`<%= workspaceDir %>/.pi/` 仍然可以作为本地调试覆盖层，但不再作为这些资源的源码真身。当前项目也会显式关闭 `AGENTS.md` 自动加载，避免工作区目录里的上下文文件混入 bot 运行时。

默认主模型来自：

```json
{
  "agents": {
    "defaults": {
      "thinkingLevel": "medium",
      "model": {
        "primary": "coze/glm-4-7-251222"
      }
    }
  }
}
```

provider 定义示例：

```json
{
  "models": {
    "providers": {
      "coze": {
        "api": "openai-completions",
        "apiKey": "${COZE_WORKLOAD_IDENTITY_API_KEY}",
        "baseUrl": "${COZE_INTEGRATION_MODEL_BASE_URL}",
        "models": [
          {
            "id": "glm-4-7-251222",
            "name": "GLM 4.7",
            "reasoning": false,
            "input": ["text"],
            "contextWindow": 200000,
            "maxTokens": 8192,
            "cost": {
              "input": 0,
              "output": 0,
              "cacheRead": 0,
              "cacheWrite": 0
            }
          }
        ]
      }
    }
  }
}
```

后续要扩展新的 openai-compatible provider，只需要在 `<%= workspaceDir %>/config.json` 里新增一个 provider 配置和模型定义即可。

当前 Dashboard 的模型配置页仅用于切换默认模型，不支持编辑 Provider 或模型参数。如果要扩展或修改 provider/model，仍然建议直接编辑 `<%= workspaceDir %>/config.json`。

## Feishu Debug

如果你在联调真实飞书机器人，并想排查重复回复或事件重试问题，可开启：

```bash
export PI_BOT_DEBUG_FEISHU=1
npm run dev
```

飞书 channel 会输出收到事件、过滤原因、去重结果和发送回复等关键日志。

默认情况下，飞书 channel 会在 bot 开始处理消息时给原消息加一个 `OneSecond` reaction，并在发送回复前移除它。这里的 `emojiType` 需要填写飞书文档里的 `emoji_type` 枚举值，比如 `OneSecond`、`MUSCLE`。你也可以在 `<%= workspaceDir %>/config.json` 里覆盖这个行为：

```json
{
  "channels": {
    "feishu": {
      "thinkingReaction": {
        "enabled": true,
        "emojiType": "OneSecond"
      }
    }
  }
}
```
