fix: return safe task recovery projection

This commit is contained in:
AI Bot
2026-06-06 19:12:18 +08:00
parent 1edfa6ecd5
commit 1ec6d003d1
2 changed files with 23 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ import { requireCsrfSafeMutation } from "@/lib/boss-csrf";
import {
canRetryMasterAgentTaskSafely,
getMasterAgentTask,
type MasterAgentTask,
retryRecoverableMasterAgentTask,
} from "@/lib/boss-data";
@@ -21,6 +22,24 @@ function forbidden() {
return jsonNoStore({ ok: false, message: "FORBIDDEN" }, { status: 403 });
}
function recoveryProjection(task: MasterAgentTask) {
const phase = task.phase ?? task.status;
const lastProgressAt = task.lastProgressAt ?? task.claimedAt ?? task.requestedAt;
const canRetry = canRetryMasterAgentTaskSafely(task);
return {
taskId: task.taskId,
projectId: task.projectId,
deviceId: task.deviceId,
status: task.status,
phase,
canRetry,
safeNextAction: canRetry ? "retry" : task.status === "needs_user_action" ? "user_action" : "inspect",
diagnosis: `任务处于 ${phase},最后进度时间 ${lastProgressAt}`,
lastErrorCode: task.lastErrorCode,
lastProgressAt,
};
}
export async function GET(
request: NextRequest,
context: { params: Promise<{ taskId: string }> },
@@ -39,21 +58,9 @@ export async function GET(
return forbidden();
}
const phase = task.phase ?? task.status;
const lastProgressAt = task.lastProgressAt ?? task.claimedAt ?? task.requestedAt;
const canRetry = canRetryMasterAgentTaskSafely(task);
return jsonNoStore({
ok: true,
recovery: {
taskId: task.taskId,
status: task.status,
phase,
canRetry,
safeNextAction: canRetry ? "retry" : task.status === "needs_user_action" ? "user_action" : "inspect",
diagnosis: `任务处于 ${phase},最后进度时间 ${lastProgressAt}`,
lastErrorCode: task.lastErrorCode,
lastProgressAt,
},
recovery: recoveryProjection(task),
});
}
@@ -85,7 +92,7 @@ export async function POST(
actorAccount: session.account,
reason: stringValue(body.reason) || "管理员从恢复面板重试任务",
});
return jsonNoStore({ ok: true, action, task });
return jsonNoStore({ ok: true, action, task: recoveryProjection(task) });
} catch (error) {
const message = error instanceof Error ? error.message : "TASK_RECOVERY_FAILED";
const status = message === "MASTER_AGENT_TASK_NOT_FOUND" ? 404 : 400;

View File

@@ -116,6 +116,8 @@ test("task recovery POST retry requeues only recoverable pre-turn task", async (
assert.equal(payload.ok, true);
assert.equal(payload.task.status, "queued");
assert.equal(payload.task.phase, "queued");
assert.equal("requestText" in payload.task, false);
assert.equal("executionPrompt" in payload.task, false);
const state = await data.readState();
assert.equal(state.permissionAuditLogs.some((log) => log.action === "master_agent.task_retried"), true);