Merge branch 'wsh_dev' into 'main'
fix: pipeline排序/runDic映射/label-master repeatable/达标优先级 See merge request wuyang6/zk-data-agent!4
This commit is contained in:
+51
-17
@@ -1768,12 +1768,11 @@ def create_app(state: AgentState) -> FastAPI:
|
||||
if isinstance(run_id, str) and run_id.strip():
|
||||
rid = run_id.strip()
|
||||
per_round = _resolve_run_dic_per_round(state_entries)
|
||||
# augment 处理的是「上一轮评测的错例」,产物按 R{n-1} 的 runDic 命名
|
||||
# (data_clean_<R{n-1}>/、augment_<R{n-1}>.jsonl ...),不是本轮 eval workflow
|
||||
# augment 产物的 runDic = resolve_run_ids.sh 在当轮 eval 落盘后取到的
|
||||
# max(已落盘 workflow) = 当轮 eval 自身的 workflow id,即 per_round[R{n}]
|
||||
# (不是 R{n-1},脚本取的是 eval 之后的 max,此时 max 已经包含当轮 eval)
|
||||
if step == 'augment':
|
||||
m = re.match(r'^[Rr](\d+)$', rid)
|
||||
if m and int(m.group(1)) >= 1:
|
||||
run_dic = per_round.get(f'R{int(m.group(1)) - 1}')
|
||||
pass # 直接走下面 per_round.get(rid) 取本轮 runDic
|
||||
if run_dic is None:
|
||||
run_dic = per_round.get(rid)
|
||||
if run_dic is None:
|
||||
@@ -6395,9 +6394,20 @@ def _build_pipeline_items(
|
||||
for c in sec['cards']:
|
||||
c.pop('_order', None)
|
||||
|
||||
# 4. Build round items in display order.
|
||||
# Order: by run_index ascending, then within same round: train before analysis.
|
||||
section_order = {'baseline': 0, 'train': 0, 'analysis': 1}
|
||||
# 3b. If a gate is running for a given run_id, downgrade running cards
|
||||
# in that run to 'waiting' (the step is blocked on human review).
|
||||
runs_with_gate_running: set[str] = set()
|
||||
for entry in latest_gate_by_key.values():
|
||||
if entry.get('status') == 'running':
|
||||
runs_with_gate_running.add(entry['_run_id'])
|
||||
if runs_with_gate_running:
|
||||
for sec in sections.values():
|
||||
if sec['run_id'] in runs_with_gate_running:
|
||||
for card in sec['cards']:
|
||||
if card['status'] == 'running':
|
||||
card['status'] = 'waiting'
|
||||
|
||||
# 4. Build round items in display order (chronological by first_ts).
|
||||
section_items: list[dict[str, Any]] = []
|
||||
for (run_id, section_type), sec in sections.items():
|
||||
run_index = _parse_run_index(run_id)
|
||||
@@ -6415,7 +6425,7 @@ def _build_pipeline_items(
|
||||
'description': _SECTION_DESCRIPTIONS[section_type],
|
||||
'status': round_status,
|
||||
'cards': sec['cards'],
|
||||
'_order_key': (run_index, section_order.get(section_type, 9), sec.get('first_ts', '')),
|
||||
'_order_key': sec.get('first_ts', ''),
|
||||
})
|
||||
|
||||
# 5. Build gate items.
|
||||
@@ -6499,7 +6509,9 @@ def _compute_in_flight(
|
||||
seen_keys: set[str] = set()
|
||||
for idx in range(len(state_entries) - 1, -1, -1):
|
||||
entry = state_entries[idx]
|
||||
if entry.get('kpi') or entry.get('log'):
|
||||
if entry.get('kpi'):
|
||||
continue
|
||||
if entry.get('log') and not entry.get('step'):
|
||||
continue
|
||||
step = entry.get('step')
|
||||
if not isinstance(step, str) or not step:
|
||||
@@ -6531,9 +6543,22 @@ def _compute_in_flight(
|
||||
if not target_run_id or not target_section:
|
||||
return None
|
||||
|
||||
# Check if a gate (human-check/human-review) is running for the target run_id
|
||||
gate_running_for_run = False
|
||||
for entry in state_entries:
|
||||
step = entry.get('step')
|
||||
if not isinstance(step, str) or not step:
|
||||
continue
|
||||
if _STEP_KIND.get(step) == 'gate' and entry.get('status') == 'running':
|
||||
entry_run_id = entry.get('run_id')
|
||||
if entry_run_id == target_run_id:
|
||||
gate_running_for_run = True
|
||||
|
||||
latest_per_step: dict[str, dict[str, Any]] = {}
|
||||
for idx, entry in enumerate(state_entries):
|
||||
if entry.get('kpi') or entry.get('log'):
|
||||
if entry.get('kpi'):
|
||||
continue
|
||||
if entry.get('log') and not entry.get('step'):
|
||||
continue
|
||||
step = entry.get('step')
|
||||
if not isinstance(step, str) or not step:
|
||||
@@ -6559,6 +6584,8 @@ def _compute_in_flight(
|
||||
status = entry.get('status')
|
||||
if status not in ('complete', 'running'):
|
||||
continue
|
||||
if status == 'running' and gate_running_for_run:
|
||||
status = 'waiting'
|
||||
meta = _CARD_META.get((step, target_section), {
|
||||
'icon': 'clock',
|
||||
'title': step,
|
||||
@@ -6634,7 +6661,9 @@ def _apply_program_state(
|
||||
# whenever a running section is hidden.
|
||||
latest_per_step: dict[str, str] = {}
|
||||
for entry in state_entries:
|
||||
if entry.get('kpi') or entry.get('log'):
|
||||
if entry.get('kpi'):
|
||||
continue
|
||||
if entry.get('log') and not entry.get('step'):
|
||||
continue
|
||||
step = entry.get('step')
|
||||
status = entry.get('status')
|
||||
@@ -6655,15 +6684,19 @@ def _apply_program_state(
|
||||
statuses = list(latest_per_step.values())
|
||||
if not statuses:
|
||||
payload['status']['state'] = 'pending'
|
||||
elif non_gate_running:
|
||||
elif non_gate_running and not gate_running:
|
||||
payload['status']['state'] = 'running'
|
||||
elif gate_running:
|
||||
# Only HiTL gates are 'running' — agent has handed control back to the
|
||||
# user. Surface as 'waiting' so the header pill says "等待人工" instead
|
||||
# of the spinning "Running" badge.
|
||||
# HiTL gate is running — agent has handed control back to the user.
|
||||
# Even if a parent step (e.g. augment) is still technically 'running',
|
||||
# the gate blocks progress. Surface as 'waiting' so the header pill
|
||||
# says "等待人工" instead of the spinning "Running" badge.
|
||||
payload['status']['state'] = 'waiting'
|
||||
elif all(s == 'complete' for s in statuses):
|
||||
payload['status']['state'] = 'complete'
|
||||
if run_active:
|
||||
payload['status']['state'] = 'running'
|
||||
else:
|
||||
payload['status']['state'] = 'complete'
|
||||
elif 'complete' in statuses:
|
||||
payload['status']['state'] = 'running'
|
||||
elif 'failed' in statuses:
|
||||
@@ -6702,6 +6735,7 @@ def _apply_program_state(
|
||||
and payload['status']['state'] == 'running'
|
||||
and running_steps
|
||||
and not all_watched
|
||||
and not gate_running
|
||||
):
|
||||
session_failure_status = 'failed'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user