fix(intelligent-eval): trigger OpenClaw planner for planning evals
All checks were successful
CI / test (push) Successful in 3m59s
All checks were successful
CI / test (push) Successful in 3m59s
方案③只自动化了 executing(worker)→completed(analyst),缺少 planning 阶段的 planner 触发——新建/被打回的评估永远停在 planning(无任何机制唤醒 agenteval-intelligent-planner skill)。 - 新增 _has_planning_eval + _trigger_intelligent_planner:scan loop 每 60s 对 planning 状态评估触发 planner skill(产出粗计划并 PUT /plan 提交), 与 worker 触发同模式(docker exec openclaw agent -m 带'立即完成'语义) - scan loop 在 worker 触发后追加 planner 触发 测试:+2(无 planning 不触发 / 有 planning 触发 planner skill),897 passed
This commit is contained in:
parent
4b66c94969
commit
9d87ecf736
@ -42,6 +42,25 @@ def _has_pending_task() -> bool:
|
|||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
def _has_planning_eval() -> bool:
|
||||||
|
"""True if any intelligent eval is waiting in ``planning`` (needs the OpenClaw planner)."""
|
||||||
|
from sqlmodel import select
|
||||||
|
|
||||||
|
from agenteval.intelligent_eval.models import IntelligentEvalStatus
|
||||||
|
from agenteval.storage.db import IntelligentEvalDB
|
||||||
|
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
ev = session.exec(
|
||||||
|
select(IntelligentEvalDB).where(
|
||||||
|
IntelligentEvalDB.status == IntelligentEvalStatus.PLANNING.value
|
||||||
|
)
|
||||||
|
).first()
|
||||||
|
return ev is not None
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
def _supplement_decision_logs(session) -> int:
|
def _supplement_decision_logs(session) -> int:
|
||||||
"""Platform audit backfill for decision logs.
|
"""Platform audit backfill for decision logs.
|
||||||
|
|
||||||
@ -206,13 +225,65 @@ async def _trigger_intelligent_worker() -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def _trigger_intelligent_planner() -> bool:
|
||||||
|
"""Trigger OpenClaw's headless agent to run the planner skill.
|
||||||
|
|
||||||
|
方案③只自动化了 executing(worker)→ completed(analyst),**缺少 planning
|
||||||
|
阶段的 planner 触发**——新建或被打回的评估会永远停在 planning。这里对
|
||||||
|
planning 状态评估触发 `agenteval-intelligent-planner` skill:planner 自会
|
||||||
|
拉取 planning 评估列表、读取四件套、产出粗计划并 PUT /plan 提交(planner
|
||||||
|
skill 定义见 OpenClaw workspace skills)。处理完评估离开 planning 后不再触发。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True 若确实触发了 agent(存在 planning 评估)。
|
||||||
|
"""
|
||||||
|
if not _has_planning_eval():
|
||||||
|
return False
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
_logger = logging.getLogger("agenteval")
|
||||||
|
# 同 worker:`openclaw agent` 无 cron state,须带"立即完成"语义,否则 planner
|
||||||
|
# 会"决策后等下一拍"而死锁。
|
||||||
|
planner_msg = (
|
||||||
|
"执行 agenteval-intelligent-planner skill,立即完成当前任务,不要等待下一节拍:"
|
||||||
|
"为 planning 状态的智能评估读取输入、产出粗计划并提交平台审批。"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
proc = await asyncio.to_thread(
|
||||||
|
subprocess.run,
|
||||||
|
[
|
||||||
|
"docker",
|
||||||
|
"exec",
|
||||||
|
"openclaw-eval",
|
||||||
|
"openclaw",
|
||||||
|
"agent",
|
||||||
|
"--agent",
|
||||||
|
"main",
|
||||||
|
"-m",
|
||||||
|
planner_msg,
|
||||||
|
"--json",
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=300,
|
||||||
|
)
|
||||||
|
_logger.info("Planner 触发完成 exit=%s", proc.returncode)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
_logger.warning("Planner 触发 stderr: %s", proc.stderr[-300:])
|
||||||
|
except Exception as exc:
|
||||||
|
_logger.warning("Planner 触发失败(忽略): %s", exc)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def _intelligent_eval_scan_loop() -> None:
|
async def _intelligent_eval_scan_loop() -> None:
|
||||||
"""Scan executing intelligent evals, enqueue tasks, and trigger the worker.
|
"""Scan intelligent evals, enqueue tasks, and trigger planner/worker.
|
||||||
|
|
||||||
v1.1.0 缺陷修复:`scan_and_enqueue_tasks` 此前没有调度点,OpenClaw Worker
|
v1.1.0 缺陷修复:`scan_and_enqueue_tasks` 此前没有调度点,OpenClaw Worker
|
||||||
每分钟唤醒却永远取不到任务。平台启动后每 60s:① 扫描 executing 的评估入队;
|
每分钟唤醒却永远取不到任务。平台启动后每 60s:
|
||||||
② 若有 pending 任务则触发 OpenClaw agent 执行 worker skill(方案③,免外部
|
① 有 planning 评估则触发 OpenClaw planner skill 产出粗计划(planning→待审批);
|
||||||
channel)。失败不阻断(下次循环继续)。
|
② 扫描 executing 的评估入队;③ 若有 pending 任务则触发 worker skill 执行会话/
|
||||||
|
分析(方案③,免外部 channel)。失败不阻断(下次循环继续)。
|
||||||
"""
|
"""
|
||||||
_logger = logging.getLogger("agenteval")
|
_logger = logging.getLogger("agenteval")
|
||||||
while True:
|
while True:
|
||||||
@ -242,6 +313,10 @@ async def _intelligent_eval_scan_loop() -> None:
|
|||||||
await _trigger_intelligent_worker()
|
await _trigger_intelligent_worker()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logging.getLogger("agenteval").warning("Worker 触发失败(忽略): %s", exc)
|
logging.getLogger("agenteval").warning("Worker 触发失败(忽略): %s", exc)
|
||||||
|
try:
|
||||||
|
await _trigger_intelligent_planner()
|
||||||
|
except Exception as exc:
|
||||||
|
logging.getLogger("agenteval").warning("Planner 触发失败(忽略): %s", exc)
|
||||||
await asyncio.sleep(60)
|
await asyncio.sleep(60)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -111,6 +111,53 @@ def test_trigger_worker_msg_has_execute_semantics(monkeypatch):
|
|||||||
assert "agenteval-intelligent-analyst" in joined
|
assert "agenteval-intelligent-analyst" in joined
|
||||||
|
|
||||||
|
|
||||||
|
def test_trigger_planner_skips_when_no_planning(monkeypatch):
|
||||||
|
"""No planning eval → no docker exec invocation."""
|
||||||
|
import asyncio
|
||||||
|
import subprocess
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
import agenteval.web.app as app_mod
|
||||||
|
|
||||||
|
calls: list = []
|
||||||
|
monkeypatch.setattr(app_mod, "_has_planning_eval", lambda: False)
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
calls.append(cmd)
|
||||||
|
return MagicMock(returncode=0, stderr="")
|
||||||
|
|
||||||
|
monkeypatch.setattr(subprocess, "run", fake_run)
|
||||||
|
|
||||||
|
assert asyncio.run(app_mod._trigger_intelligent_planner()) is False
|
||||||
|
assert not calls, "should not invoke docker exec when no planning eval"
|
||||||
|
|
||||||
|
|
||||||
|
def test_trigger_planner_calls_docker_exec(monkeypatch):
|
||||||
|
"""Planning eval present → invoke `docker exec openclaw-eval openclaw agent` planner skill."""
|
||||||
|
import asyncio
|
||||||
|
import subprocess
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
import agenteval.web.app as app_mod
|
||||||
|
|
||||||
|
calls: list = []
|
||||||
|
monkeypatch.setattr(app_mod, "_has_planning_eval", lambda: True)
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
calls.append(cmd)
|
||||||
|
return MagicMock(returncode=0, stderr="")
|
||||||
|
|
||||||
|
monkeypatch.setattr(subprocess, "run", fake_run)
|
||||||
|
|
||||||
|
assert asyncio.run(app_mod._trigger_intelligent_planner()) is True
|
||||||
|
assert calls, "docker exec should be invoked"
|
||||||
|
joined = " ".join(calls[0])
|
||||||
|
assert "docker" in joined and "openclaw" in joined
|
||||||
|
assert "agenteval-intelligent-planner" in joined
|
||||||
|
assert "立即完成当前任务" in joined
|
||||||
|
assert "不要等待下一节拍" in joined
|
||||||
|
|
||||||
|
|
||||||
def test_supplement_execute_session_log(monkeypatch, db_session):
|
def test_supplement_execute_session_log(monkeypatch, db_session):
|
||||||
"""Executing eval with deficit and no execute_session log → platform backfills."""
|
"""Executing eval with deficit and no execute_session log → platform backfills."""
|
||||||
import agenteval.web.app as app_mod
|
import agenteval.web.app as app_mod
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user