openclaw-agent-dashboard 1.0.29 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -330,6 +330,37 @@ def _clean_task_name(task_name: str) -> str:
|
|
|
330
330
|
return ''
|
|
331
331
|
|
|
332
332
|
|
|
333
|
+
def _enrich_main_agent_active_tasks_if_needed(
|
|
334
|
+
agent_active_tasks: Dict[str, List[Dict[str, Any]]],
|
|
335
|
+
main_agent_id: str,
|
|
336
|
+
) -> Dict[str, List[Dict[str, Any]]]:
|
|
337
|
+
"""
|
|
338
|
+
主 Agent 仅更新主会话、subagents/runs 无条目时,agentActiveTasks 为空;
|
|
339
|
+
在仍为 working 时补一条会话摘要,便于卡片「并行任务」区有文案。
|
|
340
|
+
"""
|
|
341
|
+
from status.status_calculator import calculate_agent_status, get_current_task
|
|
342
|
+
|
|
343
|
+
if calculate_agent_status(main_agent_id) != 'working':
|
|
344
|
+
return agent_active_tasks
|
|
345
|
+
if agent_active_tasks.get(main_agent_id):
|
|
346
|
+
return agent_active_tasks
|
|
347
|
+
hint = get_current_task(main_agent_id)
|
|
348
|
+
name = _clean_task_name(hint) if hint else ''
|
|
349
|
+
if not name:
|
|
350
|
+
return agent_active_tasks
|
|
351
|
+
merged = dict(agent_active_tasks)
|
|
352
|
+
merged[main_agent_id] = [
|
|
353
|
+
{
|
|
354
|
+
'id': 'task-main-session',
|
|
355
|
+
'name': name,
|
|
356
|
+
'status': 'working',
|
|
357
|
+
'timestamp': None,
|
|
358
|
+
'featureId': None,
|
|
359
|
+
}
|
|
360
|
+
]
|
|
361
|
+
return merged
|
|
362
|
+
|
|
363
|
+
|
|
333
364
|
def _get_agent_error_info(agent_id: str) -> Optional[Dict[str, Any]]:
|
|
334
365
|
"""获取 agent 的错误/异常信息"""
|
|
335
366
|
from session_reader import get_last_error, has_recent_errors
|
|
@@ -505,7 +536,7 @@ async def get_collaboration():
|
|
|
505
536
|
get_model_display_name, get_main_agent_id
|
|
506
537
|
)
|
|
507
538
|
from data.subagent_reader import get_active_runs
|
|
508
|
-
from status.status_calculator import calculate_agent_status
|
|
539
|
+
from status.status_calculator import calculate_agent_status, get_current_task
|
|
509
540
|
|
|
510
541
|
nodes = []
|
|
511
542
|
edges = []
|
|
@@ -555,6 +586,8 @@ async def get_collaboration():
|
|
|
555
586
|
break
|
|
556
587
|
if not main_current_task and active_runs:
|
|
557
588
|
main_current_task = _clean_task_name(active_runs[0].get('task', ''))
|
|
589
|
+
if not main_current_task:
|
|
590
|
+
main_current_task = _clean_task_name(get_current_task(main_agent_id))
|
|
558
591
|
main_error = _get_agent_error_info(main_agent_id)
|
|
559
592
|
main_stuck = _check_agent_stuck(main_agent_id)
|
|
560
593
|
|
|
@@ -773,7 +806,10 @@ async def get_collaboration():
|
|
|
773
806
|
depths[aid] = 1
|
|
774
807
|
|
|
775
808
|
# 构建多任务并行数据
|
|
776
|
-
agent_active_tasks =
|
|
809
|
+
agent_active_tasks = _enrich_main_agent_active_tasks_if_needed(
|
|
810
|
+
_build_agent_active_tasks(active_runs, main_agent_id),
|
|
811
|
+
main_agent_id,
|
|
812
|
+
)
|
|
777
813
|
|
|
778
814
|
return CollaborationFlow(
|
|
779
815
|
nodes=nodes,
|
|
@@ -849,20 +885,8 @@ async def get_collaboration_dynamic():
|
|
|
849
885
|
except Exception as e:
|
|
850
886
|
logger.warning(f"Failed to get display status for {aid}: {e}")
|
|
851
887
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
# 获取主 agent 的详细显示状态
|
|
856
|
-
try:
|
|
857
|
-
main_dyn_status = get_display_status(main_agent_id)
|
|
858
|
-
agent_dynamic_statuses[main_agent_id] = AgentDisplayStatus(
|
|
859
|
-
status=main_dyn_status['status'],
|
|
860
|
-
display=main_dyn_status['display'],
|
|
861
|
-
duration=main_dyn_status['duration'],
|
|
862
|
-
alert=main_dyn_status['alert']
|
|
863
|
-
)
|
|
864
|
-
except Exception as e:
|
|
865
|
-
logger.warning(f"Failed to get display status for {main_agent_id}: {e}")
|
|
888
|
+
# 主 Agent 状态已在上方循环中与 calculate_agent_status 一致,勿再用「有无 active_runs」覆盖
|
|
889
|
+
# (独立 PM 仅更新主会话时 runs 可能为空,否则会误显示空闲)
|
|
866
890
|
|
|
867
891
|
# 处理活跃任务(简化:不在流程图中创建任务节点,任务信息由 agentActiveTasks 提供)
|
|
868
892
|
# 任务详情在 Agent 卡片内显示,流程图只显示 Agent 之间的委托关系
|
|
@@ -896,7 +920,10 @@ async def get_collaboration_dynamic():
|
|
|
896
920
|
]
|
|
897
921
|
|
|
898
922
|
# 构建多任务并行数据
|
|
899
|
-
agent_active_tasks =
|
|
923
|
+
agent_active_tasks = _enrich_main_agent_active_tasks_if_needed(
|
|
924
|
+
_build_agent_active_tasks(active_runs, main_agent_id),
|
|
925
|
+
main_agent_id,
|
|
926
|
+
)
|
|
900
927
|
|
|
901
928
|
return CollaborationDynamic(
|
|
902
929
|
activePath=list(set(active_path)),
|
|
@@ -136,6 +136,29 @@ def get_recent_messages(agent_id: str, limit: int = 10) -> List[Dict[str, Any]]:
|
|
|
136
136
|
return messages[-limit:] if len(messages) > limit else messages
|
|
137
137
|
|
|
138
138
|
|
|
139
|
+
def get_latest_user_message_text(agent_id: str, scan_limit: int = 80) -> str:
|
|
140
|
+
"""
|
|
141
|
+
从最新会话中取最近一条 user 消息的文本(不做截断)。
|
|
142
|
+
用于无 subagent run 时展示当前任务摘要(独立 PM / 仅主会话)。
|
|
143
|
+
"""
|
|
144
|
+
messages = get_recent_messages(agent_id, limit=scan_limit)
|
|
145
|
+
for msg in reversed(messages):
|
|
146
|
+
if msg.get('role') != 'user':
|
|
147
|
+
continue
|
|
148
|
+
content = msg.get('content', [])
|
|
149
|
+
if isinstance(content, str):
|
|
150
|
+
t = content.strip()
|
|
151
|
+
if t:
|
|
152
|
+
return t
|
|
153
|
+
elif isinstance(content, list):
|
|
154
|
+
for c in content:
|
|
155
|
+
if isinstance(c, dict) and c.get('type') == 'text':
|
|
156
|
+
t = (c.get('text') or '').strip()
|
|
157
|
+
if t:
|
|
158
|
+
return t
|
|
159
|
+
return ''
|
|
160
|
+
|
|
161
|
+
|
|
139
162
|
def has_recent_errors(agent_id: str, minutes: int = 5) -> bool:
|
|
140
163
|
"""检查最近是否有错误"""
|
|
141
164
|
messages = get_recent_messages(agent_id, limit=50)
|
|
@@ -9,7 +9,7 @@ sys.path.append(str(Path(__file__).parent.parent))
|
|
|
9
9
|
import logging
|
|
10
10
|
import time
|
|
11
11
|
from typing import Literal, Dict, Any, List, Optional
|
|
12
|
-
from data.config_reader import get_agents_list, get_agent_config
|
|
12
|
+
from data.config_reader import get_agents_list, get_agent_config, get_main_agent_id
|
|
13
13
|
from data.subagent_reader import is_agent_working, get_agent_runs
|
|
14
14
|
from data.session_reader import (
|
|
15
15
|
has_recent_errors,
|
|
@@ -105,19 +105,34 @@ def get_agents_with_status() -> list:
|
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def get_current_task(agent_id: str) -> str:
|
|
108
|
-
"""
|
|
108
|
+
"""
|
|
109
|
+
获取 Agent 当前任务描述。
|
|
110
|
+
优先 subagents/runs.json 中该 Agent 作为执行者的记录。
|
|
111
|
+
子 Agent 任务仅来自 runs(业务上不存在「仅有会话、无 run」的工作态)。
|
|
112
|
+
主 Agent 无 run 时,仅在仍活跃时用主会话最近一条 user 消息作摘要,避免空闲时显示陈旧文案。
|
|
113
|
+
"""
|
|
109
114
|
runs = get_agent_runs(agent_id, limit=1)
|
|
110
|
-
if
|
|
115
|
+
if runs:
|
|
116
|
+
task = runs[0].get('task', '') or ''
|
|
117
|
+
if len(task) > 60:
|
|
118
|
+
task = task[:57] + '...'
|
|
119
|
+
return task
|
|
120
|
+
|
|
121
|
+
if agent_id != get_main_agent_id():
|
|
111
122
|
return ''
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
if not is_agent_working(agent_id) and not has_recent_session_activity(agent_id, minutes=2):
|
|
125
|
+
return ''
|
|
115
126
|
|
|
116
|
-
|
|
117
|
-
if len(task) > 60:
|
|
118
|
-
task = task[:57] + '...'
|
|
127
|
+
from data.session_reader import get_latest_user_message_text
|
|
119
128
|
|
|
120
|
-
|
|
129
|
+
text = get_latest_user_message_text(agent_id)
|
|
130
|
+
if not text:
|
|
131
|
+
return ''
|
|
132
|
+
text = ' '.join(text.split())
|
|
133
|
+
if len(text) > 60:
|
|
134
|
+
text = text[:57] + '...'
|
|
135
|
+
return text
|
|
121
136
|
|
|
122
137
|
|
|
123
138
|
def get_last_active_time(agent_id: str) -> int:
|
package/openclaw.plugin.json
CHANGED