feat(tasks): 任务列表新增「运行中 Worker」列
TaskListMetricsAll 增加一个 LATERAL 子查询统计 kind='intent' 且 state='running' 的节点数,随 TaskDTO.in_flight 一并返回,口径与任务 详情页概览的「运行中 Worker」完全一致。列表页在「目标进度」后新增该 列,无运行中 Worker 时显示 0。
This commit is contained in:
1 parent
4fba36b73d
commit
f270ca66bc
4 files changed
+22
-4
No files matched your search
+12
-4
@@ -1064,9 +1064,10 @@ type GoalCounts struct{ Total, Met int }
|
|||||||
|
|
||||||
// TaskListMetrics contains the aggregates rendered in task lists.
|
// TaskListMetrics contains the aggregates rendered in task lists.
|
||||||
type TaskListMetrics struct {
|
type TaskListMetrics struct {
|
||||||
Tokens TokenUsage
|
Tokens TokenUsage
|
||||||
LastActivity int64
|
LastActivity int64
|
||||||
Goals GoalCounts
|
Goals GoalCounts
|
||||||
|
RunningIntents int // kind='intent' 且 state='running' 的条数,即运行中 Worker 数
|
||||||
}
|
}
|
||||||
|
|
||||||
// TaskListMetricsAll returns list aggregates for every live task in one query.
|
// TaskListMetricsAll returns list aggregates for every live task in one query.
|
||||||
@@ -1081,7 +1082,8 @@ func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error) {
|
|||||||
COALESCE(token_metrics.cache_write_tokens,0),
|
COALESCE(token_metrics.cache_write_tokens,0),
|
||||||
COALESCE(latest_activity.created_at,0),
|
COALESCE(latest_activity.created_at,0),
|
||||||
COALESCE(goal_metrics.total,0),
|
COALESCE(goal_metrics.total,0),
|
||||||
COALESCE(goal_metrics.met,0)
|
COALESCE(goal_metrics.met,0),
|
||||||
|
COALESCE(intent_metrics.running,0)
|
||||||
FROM tasks task
|
FROM tasks task
|
||||||
LEFT JOIN LATERAL (
|
LEFT JOIN LATERAL (
|
||||||
SELECT SUM(input_tokens) AS input_tokens,
|
SELECT SUM(input_tokens) AS input_tokens,
|
||||||
@@ -1104,6 +1106,11 @@ func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error) {
|
|||||||
FROM exploration_nodes
|
FROM exploration_nodes
|
||||||
WHERE exploration_id=task.exploration_id AND kind='goal'
|
WHERE exploration_id=task.exploration_id AND kind='goal'
|
||||||
) goal_metrics ON true
|
) goal_metrics ON true
|
||||||
|
LEFT JOIN LATERAL (
|
||||||
|
SELECT COUNT(*) AS running
|
||||||
|
FROM exploration_nodes
|
||||||
|
WHERE exploration_id=task.exploration_id AND kind='intent' AND state='running'
|
||||||
|
) intent_metrics ON true
|
||||||
WHERE task.deleted_at IS NULL`)
|
WHERE task.deleted_at IS NULL`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1122,6 +1129,7 @@ func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error) {
|
|||||||
&metrics.LastActivity,
|
&metrics.LastActivity,
|
||||||
&metrics.Goals.Total,
|
&metrics.Goals.Total,
|
||||||
&metrics.Goals.Met,
|
&metrics.Goals.Met,
|
||||||
|
&metrics.RunningIntents,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ type TaskDTO struct {
|
|||||||
Tokens TokenTotalDTO `json:"tokens"` // whole-task token consumption
|
Tokens TokenTotalDTO `json:"tokens"` // whole-task token consumption
|
||||||
GoalsTotal int `json:"goals_total"`
|
GoalsTotal int `json:"goals_total"`
|
||||||
GoalsMet int `json:"goals_met"`
|
GoalsMet int `json:"goals_met"`
|
||||||
|
InFlight int `json:"in_flight"` // 运行中 Worker 数(state=running 的意图)
|
||||||
LLMProfileID *int64 `json:"llm_profile_id,omitempty"` // LLM profile used for this task; nil = default
|
LLMProfileID *int64 `json:"llm_profile_id,omitempty"` // LLM profile used for this task; nil = default
|
||||||
LLMProfileIDs []int64 `json:"llm_profile_ids"`
|
LLMProfileIDs []int64 `json:"llm_profile_ids"`
|
||||||
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
|
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
|
||||||
|
|||||||
@@ -1064,6 +1064,7 @@ func (s *Server) listTasks(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
dto.GoalsTotal = metric.Goals.Total
|
dto.GoalsTotal = metric.Goals.Total
|
||||||
dto.GoalsMet = metric.Goals.Met
|
dto.GoalsMet = metric.Goals.Met
|
||||||
|
dto.InFlight = metric.RunningIntents
|
||||||
dtos = append(dtos, dto)
|
dtos = append(dtos, dto)
|
||||||
}
|
}
|
||||||
writeJSON(w, 200, map[string]any{"tasks": dtos, "active": active})
|
writeJSON(w, 200, map[string]any{"tasks": dtos, "active": active})
|
||||||
|
|||||||
@@ -948,6 +948,7 @@ export default function TasksPage() {
|
|||||||
onSort={sortTasksBy}
|
onSort={sortTasksBy}
|
||||||
/>
|
/>
|
||||||
<TableHead className="text-center">目标进度</TableHead>
|
<TableHead className="text-center">目标进度</TableHead>
|
||||||
|
<TableHead className="text-center">运行中 Worker</TableHead>
|
||||||
<SortableTaskHead
|
<SortableTaskHead
|
||||||
field="created"
|
field="created"
|
||||||
label="创建时间"
|
label="创建时间"
|
||||||
@@ -1210,6 +1211,13 @@ const TaskRow = React.memo(function TaskRow({
|
|||||||
<span className="text-muted-foreground">—</span>
|
<span className="text-muted-foreground">—</span>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="text-center text-xs tabular-nums">
|
||||||
|
{task.in_flight && task.in_flight > 0 ? (
|
||||||
|
<span className="text-foreground font-medium">{task.in_flight}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-muted-foreground">0</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="text-muted-foreground text-right text-xs whitespace-nowrap tabular-nums">
|
<TableCell className="text-muted-foreground text-right text-xs whitespace-nowrap tabular-nums">
|
||||||
{fmtDateTime(task.created_unix)}
|
{fmtDateTime(task.created_unix)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
Reference in new issue
Block a user