新增任务实时详情:Agent实时状态上报(决策/执行/验证阶段)+前端详情面板(2.5s轮询步骤日志/截图/停止按钮);修复static路径
This commit is contained in:
@@ -99,6 +99,18 @@ class TaskRunner(threading.Thread):
|
||||
self.stop_flag = threading.Event()
|
||||
self.task_dir = os.path.join(TASKS_DIR, task_id)
|
||||
os.makedirs(self.task_dir, exist_ok=True)
|
||||
# 实时状态(供 API 轮询展示)
|
||||
self.current = {
|
||||
'phase': '排队中', 'step': 0, 'reason': '', 'action': '',
|
||||
'target': '', 'value': '', 'detail': '', 'ts': '',
|
||||
'elapsed': 0, 'started': False,
|
||||
}
|
||||
|
||||
def _set_current(self, **kw):
|
||||
self.current.update(kw)
|
||||
self.current['ts'] = time.strftime('%H:%M:%S')
|
||||
if self.current.get('started'):
|
||||
self.current['elapsed'] = int(time.time() - self.current.get('start_ts', time.time()))
|
||||
|
||||
def stop(self):
|
||||
self.stop_flag.set()
|
||||
@@ -118,15 +130,18 @@ class TaskRunner(threading.Thread):
|
||||
def run(self):
|
||||
update_task(self.task_id, status='running', started_at=time.time(),
|
||||
result='running')
|
||||
self._set_current(phase='启动中', started=True, start_ts=time.time())
|
||||
steps = []
|
||||
browser = None
|
||||
try:
|
||||
browser = AgentBrowser(namespace=f'task-{self.task_id}')
|
||||
deadline = time.time() + self.timeout
|
||||
self._set_current(phase='打开页面', detail=self.url)
|
||||
self._log(f'打开页面: {self.url}')
|
||||
browser.open(self.url, timeout=60)
|
||||
browser.wait('--load', 'networkidle', timeout=45)
|
||||
self._log('页面已打开')
|
||||
self._set_current(phase='页面已打开')
|
||||
|
||||
step_n = 0
|
||||
while step_n < self.max_steps:
|
||||
@@ -139,6 +154,8 @@ class TaskRunner(threading.Thread):
|
||||
|
||||
step_n += 1
|
||||
self._log(f'--- 步骤 {step_n}/{self.max_steps} ---')
|
||||
self._set_current(phase='分析页面', step=step_n,
|
||||
detail=f'正在获取页面元素快照')
|
||||
|
||||
# 1. 快照
|
||||
try:
|
||||
@@ -151,6 +168,8 @@ class TaskRunner(threading.Thread):
|
||||
cur_title = browser.title()
|
||||
|
||||
# 2. LLM 决策
|
||||
self._set_current(phase='AI 决策中', step=step_n,
|
||||
detail='正在分析页面并决定下一步动作...')
|
||||
user_msg = (
|
||||
f'## 测试目标\n{self.goal}\n\n'
|
||||
f'## 当前页面\nURL: {cur_url}\n标题: {cur_title}\n\n'
|
||||
@@ -172,11 +191,18 @@ class TaskRunner(threading.Thread):
|
||||
if action not in ('click', 'fill', 'select', 'press', 'wait',
|
||||
'scroll', 'screenshot', 'assert', 'done', 'fail'):
|
||||
self._log(f'非法动作: {action}')
|
||||
self._set_current(phase='动作异常', step=step_n,
|
||||
action=action, detail=f'非法动作: {action}')
|
||||
steps.append(self._record(step_n, decision, 'error',
|
||||
f'非法动作: {action}'))
|
||||
continue
|
||||
|
||||
# 3. 执行动作(带自愈重试)
|
||||
self._set_current(phase='执行动作', step=step_n,
|
||||
action=action, target=decision.get('target', ''),
|
||||
value=decision.get('value', ''),
|
||||
reason=decision.get('reason', ''),
|
||||
detail=f'{action} {decision.get("target", "")} {decision.get("value", "")}'.strip())
|
||||
result, detail, extra = self._execute(browser, decision)
|
||||
self._log(f'动作 {action} -> {result} {detail}')
|
||||
|
||||
@@ -243,6 +269,9 @@ class TaskRunner(threading.Thread):
|
||||
for attempt in range(MAX_RETRY_SAME_ERROR + 1):
|
||||
if attempt > 0:
|
||||
self._log(f'重试 {attempt}: {action} {target}')
|
||||
self._set_current(phase='自愈重试', step=self.current.get('step', 0),
|
||||
action=action, target=target,
|
||||
detail=f'第 {attempt} 次重试: {action} {target}')
|
||||
try:
|
||||
if action == 'click':
|
||||
browser.click(self._resolve(target))
|
||||
@@ -382,6 +411,8 @@ class TaskRunner(threading.Thread):
|
||||
return bool(r)
|
||||
|
||||
def _finish(self, browser, result, summary, steps):
|
||||
self._set_current(phase='完成', step=len(steps),
|
||||
detail=f'结果: {result} - {summary}')
|
||||
if browser:
|
||||
browser.close()
|
||||
update_task(self.task_id, status='finished', result=result,
|
||||
|
||||
Reference in New Issue
Block a user