diff --git a/apps/presentation/dashboard/src/data/chat.ts b/apps/presentation/dashboard/src/data/chat.ts index d3215c14f7..00f7470caf 100644 --- a/apps/presentation/dashboard/src/data/chat.ts +++ b/apps/presentation/dashboard/src/data/chat.ts @@ -1109,14 +1109,17 @@ export function readManagedGoalResult(goalId: string, todoId: string) { ); } export type DelegationState = "unavailable" | "accepted" | "rejected" | "recovery_required" - | "executing" | "validating" | "dispatched" | "unknown"; + | "stopped" | "executing" | "validating" | "dispatched" | "unknown"; type DelegationStateFacts = {status: string; worker_active?: boolean; recovery_required: boolean | null}; // Keep inventory and selected-operation labels consistent; unknown states stay unknown. -// "executing" and "validating" require an active worker observation, never the stored status alone. export function delegationState(row: DelegationStateFacts): DelegationState { if (row.status === "unavailable") return "unavailable"; if (row.status === "accepted") return "accepted"; if (row.status === "rejected") return "rejected"; + // A recorded stop precedes recovery: only the separate stop receipt proves + // the original execution released its Host group, so the stored status alone + // must not be read as work still needing recovery. + if (row.status === "stopped") return "stopped"; if (row.recovery_required) return "recovery_required"; if (row.status === "running" && row.worker_active) return "executing"; if (row.status === "turn_returned" && row.worker_active) return "validating"; @@ -1127,6 +1130,7 @@ const DELEGATION_STATE_LABELS: Record unavailable: {zh: "无法核验", en: "Unavailable"}, accepted: {zh: "已通过当前验收", en: "Currently accepted"}, rejected: {zh: "未通过验收", en: "Rejected"}, + stopped: {zh: "停止已登记", en: "Stop recorded"}, recovery_required: {zh: "需要恢复原执行", en: "Original execution needs recovery"}, executing: {zh: "执行中", en: "Executing"}, validating: {zh: "正在验收", en: "Validating"}, diff --git a/apps/presentation/dashboard/src/features/personal-workspace/goal-team-work.tsx b/apps/presentation/dashboard/src/features/personal-workspace/goal-team-work.tsx index fe9953c006..f9373651bc 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/goal-team-work.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/goal-team-work.tsx @@ -7,19 +7,21 @@ import {DelegationPreflightStatus} from "./delegation-preflight-status"; type Member = {id: string; agent_id: string; todo_id: string}; type DelegationRecord = DelegationInventory["items"][number]; -type PulseBucket = "executing" | "validating" | "accepted" | "attention" | "dispatched" | "unknown"; +type PulseBucket = "executing" | "validating" | "accepted" | "attention" | "stopped" | "dispatched" | "unknown"; type CheckTone = "unchecked" | "ready" | "unverified" | "blocked"; const PULSE_BUCKETS: Record = { executing: "executing", validating: "validating", accepted: "accepted", rejected: "attention", recovery_required: "attention", unavailable: "attention", - dispatched: "dispatched", unknown: "unknown", + // A recorded stop is not proof its Host group released; it is its own bucket. + stopped: "stopped", dispatched: "dispatched", unknown: "unknown", }; const PULSE_LABELS: Record = { executing: {zh: "执行中", en: "Executing"}, validating: {zh: "正在验收", en: "Validating"}, accepted: {zh: "已通过", en: "Accepted"}, attention: {zh: "需要处理", en: "Needs attention"}, + stopped: {zh: "已登记停止", en: "Stop on record"}, dispatched: {zh: "等待回读", en: "Awaiting readback"}, unknown: {zh: "状态未知", en: "Unknown"}, }; @@ -41,6 +43,8 @@ function StateIcon({state}: {state: DelegationState | PulseBucket | CheckTone}) if (state === "validating") return