# Arena Monitor

> Scrape training metrics from Tencent AI Arena (tencentarena.com) monitoring dashboard. Covers JWT auth, x-kaiwu-auth signature, API endpoints, and metric extraction.

- Skill: `piaoxuemoli/arena-monitor` (Agent Skill)
- Install (CLI): `npx skillmds@latest add piaoxuemoli/arena-monitor`
- Raw SKILL.md: https://api.skillmd.com/api/skills/piaoxuemoli/arena-monitor/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: piaoxuemoli (https://skillmd.com/u/piaoxuemoli)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/piaoxuemoli/arena-monitor

---


# Arena Monitor

从腾讯开悟平台 (tencentarena.com) 抓取训练监控数据。

## 认证机制

### Token

JWT token 从浏览器 cookie `kaiwu-token` 获取，同时作为 `Authorization: Bearer` 头。

JWT payload 包含：
- `custom`: user_id（如 15850）
- `exp`: 过期时间（通常 7 天）
- `iss`: "kaiwu"

### x-kaiwu-auth 签名

每个 API 请求需要两个自定义头：

```
x-kaiwu-ts: <当前 Unix 时间戳（秒）>
x-kaiwu-auth: DJB2_HASH(timestamp + token_last_32_chars + url_last_path_segment)
```

DJB2 hash 实现（JavaScript 源码）：
```javascript
function k9(t) {
    return function(t, e) {
        for (var r = 5381, n = 0, o = e.length; n < o; ++n)
            r += (r << 5) + e.charCodeAt(n);
        return 2147483647 & r
    }(0, t)
}
```

Python 实现：
```python
def kaiwu_auth_hash(timestamp: int, token: str, url_path: str) -> int:
    last32 = token[-32:]
    last_segment = url_path.rstrip('/').split('/')[-1]
    data = f"{timestamp}{last32}{last_segment}"
    r = 5381
    for c in data:
        r = (r + (r << 5) + ord(c)) & 0xFFFFFFFF
    return r & 2147483647
```

### 完整请求头

```
Cookie: select_lang=zh; kaiwu-token=<JWT>
Authorization: Bearer <JWT>
x-kaiwu-auth: <hash>
x-kaiwu-ts: <timestamp>
Referer: https://tencentarena.com/p/v5/exp/monitor
```

## API 端点

基础路径：`https://tencentarena.com/api/v5/Competition/`

| 端点 | 方法 | 说明 |
|------|------|------|
| `GetTrainTask` | POST | 获取训练任务信息 |
| `GetTrainLog` | POST | 获取训练日志 |
| `GetTrainMetric` | POST | 获取指标数据（PromQL 查询） |
| `GetTrainMetricRange` | POST | 获取指标时间范围 |
| `ListTrainTask` | POST | 列出训练任务 |
| `ListTrainAiModel` | POST | 列出训练模型 |
| `GetExperiment` | POST | 获取实验信息 |

### 请求体结构

```json
{
  "domain": {"type": "competition_stage", "id": 444},
  "train_task_id": 183628,
  "competition_team_id": 7203,
  "experiment_id": 11425,
  "start_time": {"timestamp": "2026-05-27T16:00:00Z"},
  "end_time": {"timestamp": "2026-05-28T02:00:00Z"},
  "queries": [
    {"expr": "round(avg(kaiwu_win_rate{model_id=\"selfplay\"}) by (model_id), 0.01)"}
  ]
}
```

## 监控指标

### 基础指标（6 项）
- `kaiwu_train_global_step` — 全局训练步数
- `kaiwu_actor_predict_succ_cnt` — Actor 预测成功数
- `kaiwu_sample_production_and_consumption_ratio` — 样本生产消费比
- `kaiwu_episode_cnt` — 对局数
- `kaiwu_actor_load_last_model_succ_cnt` — Actor 加载最新模型成功数
- `kaiwu_sample_receive_cnt` — 样本接收数

### 环境指标（6 项）
- `kaiwu_win_rate` — 胜率（selfplay 对局）
- `kaiwu_self_tower_hp` / `kaiwu_enemy_tower_hp` — 塔血量
- `kaiwu_frame` — 对局帧数
- `kaiwu_kill` / `kaiwu_death` — 击杀/死亡数
- `kaiwu_money_per_frame` — 每帧经济
- `kaiwu_hurt_to_hero` / `kaiwu_hurt_by_hero` — 每帧伤害

### 评估指标（6 项）
- 跨英雄胜率：`kaiwu_direnjie_vs_luban_win_rate`、`kaiwu_luban_vs_direnjie_win_rate`
- 评估英雄胜率：`kaiwu_eval_luban_win_rate`、`kaiwu_eval_direnjie_win_rate`
- 英雄召唤师胜率：`kaiwu_luban_summoner_win_rate`、`kaiwu_direnjie_summoner_win_rate`

### 算法损失（5 项）
- `kaiwu_total_loss`、`kaiwu_value_loss`、`kaiwu_policy_loss`、`kaiwu_entropy_loss`
- Value loss 分项：`kaiwu_value_loss_hp`、`kaiwu_value_loss_tower`、`kaiwu_value_loss_econ`、`kaiwu_value_loss_combat`

### 优化器状态（3 项）
- `kaiwu_learning_rate`、`kaiwu_entropy_beta`、`kaiwu_grad_norm`

### 训练吞吐（2 项）
- `kaiwu_sample_batch_size`、`kaiwu_train_step`

### 奖励指标（3 项）
- `kaiwu_reward`（平台累积回报）、`kaiwu_reward_sum`（对局总回报）
- 奖励分项：`kaiwu_reward_hp`、`kaiwu_reward_tower`、`kaiwu_reward_econ`、`kaiwu_reward_combat`

### 对局质量（2 项）
- `kaiwu_episode_frame`、`kaiwu_episode_win_value`

## SSR 数据提取

监控页面是 Next.js RSC (React Server Components) 应用。页面 HTML 中嵌入了：
- 任务信息（status, algorithm, training_mode, version）
- Dashboard 配置（指标名 + PromQL 表达式）
- React Query state（task data, time range）

提取方法：用 curl 带认证头请求页面 URL，然后从 `self.__next_f.push([1, "..."])` payload 中解析 JSON。

## 已知参数（当前任务）

| 参数 | 值 |
|------|------|
| task_id | 189696 |
| task_uuid | 57738cce-5bfb-4183-8ab2-37b57bb407cb |
| team_id | 7203 |
| domain_id | 444 |
| exp_id | 11425 |
| algorithm | PPO |
| training_mode | Distributed |
| status | running |

## Pitfalls

1. **x-kaiwu-auth 不是固定值** — 每次请求需要用当前时间戳重新计算
2. **x-kaiwu-ts 必须是当前时间** — 过期的 timestamp 会返回 1401 非法请求
3. **JWT 有效期 7 天** — 过期后需要用户重新登录获取新 token
4. **SSR 数据不含实际指标值** — 只有 dashboard 配置，实际数据需要客户端 API 请求
5. **PromQL 表达式中的引号需要转义** — JSON 中 `model_id=\"selfplay\"` 需要反斜杠转义
6. **hash 函数可能因版本更新变化** — 如果认证失败，重新检查 JS chunk 中的 k9 实现

