From 1ec6d003d1f131b6c80dc611adf009ed3c78e5f4 Mon Sep 17 00:00:00 2001 From: AI Bot Date: Sat, 6 Jun 2026 19:12:18 +0800 Subject: [PATCH] fix: return safe task recovery projection --- .../tasks/[taskId]/recovery/route.ts | 35 +++++++++++-------- .../master-agent-task-recovery-route.test.ts | 2 ++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/app/api/v1/master-agent/tasks/[taskId]/recovery/route.ts b/src/app/api/v1/master-agent/tasks/[taskId]/recovery/route.ts index 39f798d..b111ec2 100644 --- a/src/app/api/v1/master-agent/tasks/[taskId]/recovery/route.ts +++ b/src/app/api/v1/master-agent/tasks/[taskId]/recovery/route.ts @@ -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; diff --git a/tests/master-agent-task-recovery-route.test.ts b/tests/master-agent-task-recovery-route.test.ts index 27d8ed6..2258c44 100644 --- a/tests/master-agent-task-recovery-route.test.ts +++ b/tests/master-agent-task-recovery-route.test.ts @@ -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);