|
@@ -203,8 +203,100 @@ sqlite3 <hermes>/executions.db "SELECT * FROM executions ORDER BY started_at DES
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 三、验收清单(9 条,缺一不可)
|
|
|
|
|
|
|
+## 三、任务状态字段怎么填(Hermes 容器必读)
|
|
|
|
|
|
|
|
|
|
+> 🔴 这一节解决的是:**「当前任务」和「容器状态」该从哪来。**
|
|
|
|
|
+> 填错会让用户看到"永远正在执行",或看到上报器自己的活动被当成业务任务。
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 语义定义(先分清两件事)
|
|
|
|
|
+
|
|
|
|
|
+| 字段 | 语义 | ❌ 常见错误 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `status` | 容器**有没有在为用户干活** | 硬编码 `running`,永远显示"正在执行" |
|
|
|
|
|
+| `currentTask` | **为用户**正在执行的任务 | 填上报器自己的活动(`periodic status reporter`)|
|
|
|
|
|
+| `currentAction` | 该任务的具体动作 | 填 `reporter heartbeat @ <时间>` |
|
|
|
|
|
+| `progress` | 任务进度 0~100 | 没有真实数据时编一个数 |
|
|
|
|
|
+
|
|
|
|
|
+**判据**:这三个字段描述的是**用户的业务**,不是**上报进程自己**。
|
|
|
|
|
+
|
|
|
|
|
+### 3.2 Hermes 的任务模型(代码级实证)
|
|
|
|
|
+
|
|
|
|
|
+**Hermes 没有独立"任务"对象,任务 = 一个 turn(回合)。**
|
|
|
|
|
+
|
|
|
|
|
+权威信号在 `state.db` 的 `sessions` 表:
|
|
|
|
|
+
|
|
|
|
|
+| 字段 | 语义 | turn 结束时 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `last_activity_at` | 最近活动时间戳 | 保留(时钟连续)|
|
|
|
|
|
+| `last_activity_description` | 当前活动描述(**中文**)| **清空为 `""`** |
|
|
|
|
|
+
|
|
|
|
|
+源码依据:`/opt/hermes/agent/activity_tracking.py:120-138`
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+def reset_activity_labels_after_turn(self):
|
|
|
|
|
+ """Drop mid-turn activity labels once the turn is no longer running.
|
|
|
|
|
+ Keeps last_activity_ts so idle/watchdog clocks stay continuous across turns;
|
|
|
|
|
+ clears description + provenance so idle agents / SessionDB listings
|
|
|
|
|
+ stop advertising the last mid-turn stamp."""
|
|
|
|
|
+ self.last_activity_desc = ""
|
|
|
|
|
+ self.last_activity_provenance = ActivityProvenance.UNKNOWN
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**上游自己就是靠「清空 description」来表达「不忙了」。**
|
|
|
|
|
+
|
|
|
|
|
+### 3.3 正确取值方式
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+# status:从 state.db 现场判定,不读 env、不硬编码
|
|
|
|
|
+desc = sessions.last_activity_description
|
|
|
|
|
+age = now - sessions.last_activity_at
|
|
|
|
|
+
|
|
|
|
|
+if desc and age < 180: # 有描述且新鲜 → 在干活
|
|
|
|
|
+ status = "running"
|
|
|
|
|
+elif desc == "": # 已被上游清空 → 不忙了
|
|
|
|
|
+ status = "idle"
|
|
|
|
|
+else: # DB 不可读 → 诚实报错,不伪造
|
|
|
|
|
+ status = "error"
|
|
|
|
|
+
|
|
|
|
|
+# currentTask:从 session_key 解析渠道,不硬编码
|
|
|
|
|
+currentTask = "处理{渠道}用户对话" # 如「处理企业微信用户对话」
|
|
|
|
|
+
|
|
|
|
|
+# currentAction:直接取上游原话,不加工
|
|
|
|
|
+currentAction = sessions.last_activity_description # 本身就是中文
|
|
|
|
|
+
|
|
|
|
|
+# progress:没有可靠数据 → 不填
|
|
|
|
|
+# Hermes 的 format_iteration_progress() 给的是 "iteration 3/50",
|
|
|
|
|
+# 不是用户可读的进度百分比 → 编一个数等于伪造
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**窗口为什么取 180s**:上游心跳最小间隔 60s,长回合中间可能无写入。
|
|
|
|
|
+宁短时误报 `running`,也不把正在跑的报成 `idle`。
|
|
|
|
|
+
|
|
|
|
|
+### 3.4 实测验证(2026-10-20 15:22~15:26)
|
|
|
|
|
+
|
|
|
|
|
+| 时刻 | 场景 | status | currentTask |
|
|
|
|
|
+|---|---|---|---|
|
|
|
|
|
+| 15:22 | 容器正在生成回复 | `running` | `处理企业微信用户对话` |
|
|
|
|
|
+| 15:26 | 回复结束、turn 关闭 | **`idle`** | `""`(已清空)|
|
|
|
|
|
+
|
|
|
|
|
+✅ 正确翻转,与 `reset_activity_labels_after_turn()` 的行为一致。
|
|
|
|
|
+
|
|
|
|
|
+### 3.5 🔴 禁止的做法
|
|
|
|
|
+
|
|
|
|
|
+| 做法 | 为什么不行 |
|
|
|
|
|
+|---|---|
|
|
|
|
|
+| 硬编码 `status = "running"` | 永远显示"正在执行",用户无法判断是否空闲 |
|
|
|
|
|
+| 把上报器自己的活动写进 `currentTask` | 用户看到的是监控程序在跑,不是他的任务 |
|
|
|
|
|
+| 让上报器往 `AGENT_CURRENT_TASK` env 里写 | 等于伪造业务状态;且原版脚本是**读**这个 env,不是写 |
|
|
|
|
|
+| 编一个 `progress` 数字 | 进度必须来自真实数据源 |
|
|
|
|
|
+
|
|
|
|
|
+> **实测**:某容器曾上报 `currentTask = "periodic status reporter (xlosi3m46q)"`、
|
|
|
|
|
+> `currentAction = "reporter heartbeat @ ..."` —— 三个字段全是上报器自己的活动,
|
|
|
|
|
+> 用户看到"正在执行"但实际什么都没做。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 四、验收清单(9 条,缺一不可)
|
|
|
```bash
|
|
```bash
|
|
|
curl -s 'https://server.fmode.cn/parse/classes/FmodeAgent?where={"agentId":"<容器名>"}' \
|
|
curl -s 'https://server.fmode.cn/parse/classes/FmodeAgent?where={"agentId":"<容器名>"}' \
|
|
|
-H 'X-Parse-Application-Id: ncloudmaster'
|
|
-H 'X-Parse-Application-Id: ncloudmaster'
|
|
@@ -224,7 +316,7 @@ curl -s 'https://server.fmode.cn/parse/classes/FmodeAgent?where={"agentId":"<容
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 四、🔴 四条铁律(本轮全部踩过)
|
|
|
|
|
|
|
+## 五、🔴 四条铁律(本轮全部踩过)
|
|
|
|
|
|
|
|
### 铁律 1 · 查运行态,不查路径
|
|
### 铁律 1 · 查运行态,不查路径
|
|
|
|
|
|
|
@@ -291,7 +383,7 @@ lastInboundAgeSecs = 业务活跃度(只展示,不参与健康判断)
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 五、故障速查表
|
|
|
|
|
|
|
+## 六、故障速查表
|
|
|
|
|
|
|
|
### 4.1 上报返回 `agent not found` / 数据不落库
|
|
### 4.1 上报返回 `agent not found` / 数据不落库
|
|
|
|
|
|
|
@@ -370,7 +462,7 @@ grep -iE "inbound message" /opt/data/logs/gateway.log | tail -10
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 六、给容器的标准操作提示词
|
|
|
|
|
|
|
+## 七、给容器的标准操作提示词
|
|
|
|
|
|
|
|
```markdown
|
|
```markdown
|
|
|
【容器状态上报 · 标准接入】
|
|
【容器状态上报 · 标准接入】
|
|
@@ -422,7 +514,7 @@ heartbeatAt=<回读> usage.totalTokens=<回读> balance.remainCny=<回读>
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 七、上线检查表(复制给执行人)
|
|
|
|
|
|
|
+## 八、上线检查表(复制给执行人)
|
|
|
|
|
|
|
|
```markdown
|
|
```markdown
|
|
|
□ 存活三查(ps / proc / 平台回读)已做
|
|
□ 存活三查(ps / proc / 平台回读)已做
|
|
@@ -432,14 +524,17 @@ heartbeatAt=<回读> usage.totalTokens=<回读> balance.remainCny=<回读>
|
|
|
□ 上报走 xlosi3m46q(返回不是 "key":"user/.../log/...json")
|
|
□ 上报走 xlosi3m46q(返回不是 "key":"user/.../log/...json")
|
|
|
□ 常驻用 cron 或 s6(不是 while true)
|
|
□ 常驻用 cron 或 s6(不是 while true)
|
|
|
□ 平台回读 updatedAt 在 5 分钟内
|
|
□ 平台回读 updatedAt 在 5 分钟内
|
|
|
-□ 9 条验收断言全过
|
|
|
|
|
|
|
+□ 9 条验收断言全过(§四)
|
|
|
|
|
+□ 任务状态语义正确(§三)
|
|
|
□ 机器人在 App 会话里能实际回复消息
|
|
□ 机器人在 App 会话里能实际回复消息
|
|
|
|
|
+□ status 在消息处理完后从 running 翻成 idle(不是恒 running)
|
|
|
|
|
+□ currentTask 是业务任务而非上报器自身活动
|
|
|
□ 重启 gateway 后上报能自动恢复
|
|
□ 重启 gateway 后上报能自动恢复
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-## 八、关联文档
|
|
|
|
|
|
|
+## 九、关联文档
|
|
|
|
|
|
|
|
- `docs/03-interface/reporter字段规范-20261020.md` —— 逐字段契约(改脚本时查)
|
|
- `docs/03-interface/reporter字段规范-20261020.md` —— 逐字段契约(改脚本时查)
|
|
|
- `docs/03-interface/容器初始化流程优化建议-20261020.md` —— workshop 流程优化 + 方法论
|
|
- `docs/03-interface/容器初始化流程优化建议-20261020.md` —— workshop 流程优化 + 方法论
|