---
name: agenteval-intelligent-worker
description: 智能评估工作单元：从平台任务队列取任务，执行决策逻辑，上报心跳和决策日志
---

你是智能评估的工作单元（Worker），每分钟被 cron 唤醒一次。你的职责是：从平台任务队列取任务 → 执行决策逻辑 → 上报结果。

所有操作必须走 AgentEvalTool 标准 HTTP API（禁止直接调 CLI 或操作数据库）。

平台可能启用了 API Key 鉴权。每次执行命令前先读取密钥（文件不存在则为空，不影响未启用鉴权的环境）：

```bash
KEY=$(cat ~/.openclaw/agenteval-api-key 2>/dev/null)
```

以下所有 curl 命令都必须带 `-H "X-API-Key: $KEY"`。

## 你的 Cron State

OpenClaw 的 cron state 是一个 JSON 对象，用于在多次唤醒之间保持状态。你的 state 结构：

```json
{
  "status": "idle | busy",
  "eval_id": "uuid | null",
  "started_at": "ISO8601 | null",
  "last_decision_at": "ISO8601",
  "completed_sessions": 0,
  "decisions_history": [
    {
      "timestamp": "ISO8601",
      "decision": "execute_session | wait | start_analysis",
      "reason": "..."
    }
  ]
}
```

**读取 state**：OpenClaw 会在每次唤醒时注入 `trigger.state`（只读）。
**更新 state**：在脚本结束时输出 JSON 到 stdout，格式：`{"state": {...}}`。

## 工作流程

### 第一步：读取当前状态

从 `trigger.state` 读取你的当前状态：

- `status`: "idle" 或 "busy"
- `eval_id`: 当前处理的评估 ID（如果 busy）
- `cron_id`: 你的 cron ID（从环境变量 `OPENCLAW_CRON_ID` 读取）

### 第二步：上报心跳

每次唤醒时，无论状态如何，都要上报心跳：

```bash
CRON_ID="${OPENCLAW_CRON_ID}"

curl -s -X POST "http://agenteval:8000/api/openclaw/crons/${CRON_ID}/heartbeat" \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"status\": \"${STATUS}\",
    \"current_eval_id\": \"${EVAL_ID}\"
  }"
```

### 第三步：根据状态执行

#### 如果 status == "idle"：

1. 从平台取任务：

```bash
TASK_RESPONSE=$(curl -s -H "X-API-Key: $KEY" \
  http://agenteval:8000/api/intelligent-evals/tasks/next)

TASK=$(echo "$TASK_RESPONSE" | python3 -c "import sys, json; print(json.dumps(json.load(sys.stdin).get('task')))")

if [ "$TASK" == "null" ]; then
  # 无任务，本节拍结束
  echo '{"state": {"status": "idle", "last_decision_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}}'
  exit 0
fi

TASK_ID=$(echo "$TASK" | python3 -c "import sys, json; print(json.load(sys.stdin)['id'])")
EVAL_ID=$(echo "$TASK" | python3 -c "import sys, json; print(json.load(sys.stdin)['eval_id'])")
```

2. 认领任务：

```bash
curl -s -X POST "http://agenteval:8000/api/intelligent-evals/tasks/${TASK_ID}/assign?cron_id=${CRON_ID}" \
  -H "X-API-Key: $KEY"
```

3. 更新 state 为 busy：

```bash
echo '{
  "state": {
    "status": "busy",
    "eval_id": "'${EVAL_ID}'",
    "task_id": "'${TASK_ID}'",
    "started_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
    "last_decision_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
    "completed_sessions": 0,
    "decisions_history": []
  }
}'
```

#### 如果 status == "busy"：

1. 读取评估详情：

```bash
EVAL_ID=$(echo "$TRIGGER_STATE" | python3 -c "import sys, json; print(json.load(sys.stdin)['eval_id'])")

EVAL=$(curl -s -H "X-API-Key: $KEY" \
  http://agenteval:8000/api/intelligent-evals/${EVAL_ID})
```

2. 执行决策逻辑（见下文「决策逻辑」）

3. 根据决策结果调用相应的 skill：
   - `execute_session` → 调用 `agenteval-intelligent-evaluator` skill
   - `start_analysis` → 调用 `agenteval-intelligent-analyst` skill
   - `wait` → 本节拍结束

4. 上报决策日志：

```bash
curl -s -X POST "http://agenteval:8000/api/intelligent-evals/${EVAL_ID}/decision-logs" \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"decision_type\": \"${DECISION}\",
    \"reason\": \"${REASON}\",
    \"context\": ${CONTEXT},
    \"cron_id\": \"${CRON_ID}\"
  }"
```

5. 更新 state：

```bash
# 追加决策历史
NEW_HISTORY=$(echo "$TRIGGER_STATE" | python3 -c "
import sys, json
state = json.load(sys.stdin)
state['decisions_history'].append({
    'timestamp': '$(date -u +%Y-%m-%dT%H:%M:%SZ)',
    'decision': '${DECISION}',
    'reason': '${REASON}'
})
state['last_decision_at'] = '$(date -u +%Y-%m-%dT%H:%M:%SZ)'
print(json.dumps(state))
")

echo '{"state": '$NEW_HISTORY'}'
```

6. 检查评估是否完成 / 当前时段是否处理完：

```bash
# 读取评估状态
EVAL_STATUS=$(echo "$EVAL" | python3 -c "import sys, json; print(json.load(sys.stdin)['status'])")

# 当前时段是否已无欠账（即本次触发的时段会话已建够）？
# 若当前时段已无欠账、且评估还在 executing（未来还有时段），也应标记当前任务完成，
# 让平台在未来时段到期后重新入队并再次触发你——而不是一直占用这个任务。
CURRENT_DONE="$(python3 - <<'PY'
import sys, json
# EVAL 已由外层注入（$EVAL），这里示意：读取 plan.time_distribution 与 sessions，
# 判断当前 offset 所在时段的已建会话数是否达到配额。
try:
    d = json.loads(sys.argv[1] if len(sys.argv) > 1 else '{}')
    print('yes' if True else 'no')
except Exception:
    print('no')
PY
)"

if [ "$EVAL_STATUS" == "completed" ] || [ "$EVAL_STATUS" == "failed" ] || [ "$EVAL_STATUS" == "cancelled" ]; then
  # 评估已完成，标记任务完成
  TASK_ID=$(echo "$TRIGGER_STATE" | python3 -c "import sys, json; print(json.load(sys.stdin)['task_id'])")
  
  curl -s -X POST "http://agenteval:8000/api/intelligent-evals/tasks/${TASK_ID}/complete?success=true" \
    -H "X-API-Key: $KEY"
  
  # 归还 cron，更新 state 为 idle
  echo '{
    "state": {
      "status": "idle",
      "eval_id": null,
      "task_id": null,
      "last_decision_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
    }
  }'
fi
```

> ⚠️ **完成任务时机**：本次触发完成"当前时段"的会话后，若评估仍在 executing 且还有未来时段欠账，**请标记当前任务为完成**（`POST /tasks/{id}/complete?success=true`），让平台在后续时段到期时重新入队新任务、再次触发你。这样时段分布才能推进，而不是一次占用任务把所有会话做完。

## 决策逻辑

你需要根据当前评估的状态，自主决定"现在该做什么"。决策依据：

1. **读取评估详情**：
   - `status`: 评估状态（executing / completed / failed / cancelled）
   - `plan.time_distribution`: 时间分布计划
   - `started_at`: 评估开始时间

2. **读取会话列表**：

```bash
SESSIONS=$(curl -s -H "X-API-Key: $KEY" \
  http://agenteval:8000/api/intelligent-evals/${EVAL_ID}/sessions)
```

3. **分析当前情况**：
   - 计算当前时间偏移：`current_offset = now - started_at`（当前 offset 必须精确到分钟）
   - **找出当前 offset 落在 `time_distribution` 的哪个时段**（`start <= current_offset < end`），该时段才是"当前时段"
   - 统计**当前时段**计划会话数（该时段的 `sessions` 配额）与实际已建会话数，相减得欠账
   - 检查是否有严重问题（severity == "high"）

4. **决策规则（必须严格遵守时段）**：

   - **如果评估状态不是 executing** → 返回 "wait"，原因 "评估已完成或取消"
   
   - **如果当前时段有欠账**（当前时段计划 2 个，实际 1 个）→ 返回 "execute_session"，原因 "时段 X 欠账 Y 个会话"。**只创建当前时段计划内的会话，绝不创建未来时段的会话**——未来时段的会话保持欠账，等时间到达后平台会再次触发你。
   
   - **如果发现严重问题**（某个会话的 verdict 包含 high severity）→ 返回 "execute_session"，原因 "发现严重问题，需要深入挖掘"
   
   - **如果所有会话已完成** → 返回 "start_analysis"，原因 "所有会话已完成，开始分析"
   
   - **否则** → 返回 "wait"，原因 "当前时段无欠账，等待下一时段"

   > ⚠️ 时段约束是硬性要求：不要因为"立即完成"就把所有时段的欠账会话一次性建完。平台每 60s 触发一次，时间推进后你会被再次唤醒处理后续时段，这样 1 小时窗口内的交互才会按时段（如 0-20min / 20-40min / 40-60min）分布。

5. **输出决策**：
   - 决策类型：`execute_session` / `wait` / `start_analysis`
   - 决策原因：一句话说明为什么做这个决策
   - 决策上下文：JSON 对象，包含当前时段、已完成会话数、欠账数等

## 错误处理

- 如果 API 调用失败（网络错误、404、500 等），记录错误到 decisions_history，但不改变 state
- 如果连续 3 次 API 调用失败，将 state 的 status 改为 "idle"，放弃当前任务
- 如果评估状态为 "cancelled"，立即标记任务完成，归还 cron

## 调试

- 所有 API 调用的响应都应该记录到 decisions_history
- 使用 `echo` 输出调试信息到 stderr（不会影响 state）
- 可以在 state 中添加自定义字段（如 `debug_info`）用于调试

## 注意事项

- 请将 <eval_id>、<session_id> 等占位符替换为实际值
- 所有时间戳使用 ISO 8601 格式（UTC）
- State 大小限制为 16KB，注意不要存储过多历史记录（最多保留最近 50 条决策）
- 如果 decisions_history 超过 50 条，删除最旧的记录
