feat: polish web master-agent controls and dispatch recovery

This commit is contained in:
kris
2026-04-01 07:50:20 +08:00
parent 87093677b8
commit e52932e8ef
8 changed files with 153 additions and 29 deletions

View File

@@ -4,6 +4,7 @@ import {
extractApprovedTargetProjectIds,
latestRejectedDispatchPlan,
latestPendingDispatchPlan,
resolveDispatchPlanComposerState,
summarizeDispatchPlan,
} from "@/lib/dispatch-plan-ui";
@@ -79,3 +80,54 @@ test("latestRejectedDispatchPlan returns the latest rejected item", () => {
targets: [{ projectId: "p3", threadDisplayName: "调度修复线程" }],
});
});
test("resolveDispatchPlanComposerState folds older rejected plans once a newer pending plan exists", () => {
const state = resolveDispatchPlanComposerState([
{
planId: "dispatch-plan-1",
status: "rejected",
summary: "已拒绝的推荐",
targets: [{ projectId: "p3", threadDisplayName: "调度修复线程" }],
},
{
planId: "dispatch-plan-2",
status: "pending_user_confirmation",
summary: "重新生成的推荐",
targets: [{ projectId: "p2", threadDisplayName: "设备接入线程" }],
},
]);
assert.deepEqual(state.pendingDispatchPlan, {
planId: "dispatch-plan-2",
status: "pending_user_confirmation",
summary: "重新生成的推荐",
targets: [{ projectId: "p2", threadDisplayName: "设备接入线程" }],
});
assert.equal(state.rejectedDispatchPlan, null);
assert.equal(state.recoveryHint, "当前有待确认推荐,已折叠旧的拒绝状态。");
assert.equal(state.recoveryActionLabel, null);
});
test("resolveDispatchPlanComposerState exposes a retry action for a rejected plan", () => {
const state = resolveDispatchPlanComposerState([
{
planId: "dispatch-plan-3",
status: "rejected",
summary: "已拒绝的推荐",
targets: [{ projectId: "p3", threadDisplayName: "调度修复线程" }],
},
]);
assert.equal(state.pendingDispatchPlan, null);
assert.deepEqual(state.rejectedDispatchPlan, {
planId: "dispatch-plan-3",
status: "rejected",
summary: "已拒绝的推荐",
targets: [{ projectId: "p3", threadDisplayName: "调度修复线程" }],
});
assert.equal(state.recoveryActionLabel, "重新生成新的推荐");
assert.equal(
state.recoveryHint,
"上次推荐已拒绝。直接点击“重新生成新的推荐”即可继续协作,不用重新发送整条消息。",
);
});

View File

@@ -2,15 +2,17 @@ import test from "node:test";
import assert from "node:assert/strict";
import { getMasterAgentChatMenuItems } from "../src/lib/master-agent-chat-menu";
test("master-agent 聊天页菜单包含提示词、记忆和刷新", () => {
test("master-agent 聊天页菜单包含提示词、模型、推理强度、记忆和刷新", () => {
const items = getMasterAgentChatMenuItems("master-agent");
assert.deepEqual(
items.map((item) => item.key),
["prompt", "memory", "refresh"],
["prompt", "model", "reasoning_effort", "memory", "refresh"],
);
assert.equal(items[0]?.href, "/me/master-agent#prompt-section");
assert.equal(items[1]?.href, "/me/master-agent#memory-section");
assert.equal(items[2]?.action, "refresh");
assert.equal(items[1]?.href, "/me/master-agent#model-section");
assert.equal(items[2]?.href, "/me/master-agent#reasoning-effort-section");
assert.equal(items[3]?.href, "/me/master-agent#memory-section");
assert.equal(items[4]?.action, "refresh");
});
test("普通会话不返回主 Agent 专属菜单", () => {