feat: streamline group dispatch reminders

This commit is contained in:
kris
2026-04-04 03:00:34 +08:00
parent 425d8992ef
commit 5ebb37cbfc
13 changed files with 485 additions and 37 deletions

View File

@@ -314,6 +314,7 @@ export interface Project {
createdByAgent: boolean;
collaborationMode: "development" | "approval_required";
approvalState: "not_required" | "pending_agent" | "pending_user" | "approved" | "rejected";
lightDispatchReminderEnabled?: boolean;
orchestrationBackendOverride?: OrchestrationBackendOverride;
agentControls?: ProjectAgentControls;
unreadCount: number;
@@ -371,7 +372,7 @@ export interface DispatchExecution {
}
export function buildCollaborationGate(
project?: Pick<Project, "isGroup" | "collaborationMode" | "approvalState">,
project?: Pick<Project, "isGroup" | "collaborationMode" | "approvalState" | "lightDispatchReminderEnabled">,
) {
if (!project) {
return {
@@ -379,6 +380,7 @@ export function buildCollaborationGate(
collaborationMode: "development" as const,
requiresMasterAgentApproval: false,
approvalState: "not_required" as const,
lightDispatchReminderEnabled: false,
};
}
@@ -387,6 +389,7 @@ export function buildCollaborationGate(
collaborationMode: project.collaborationMode,
requiresMasterAgentApproval: project.isGroup && project.collaborationMode === "approval_required",
approvalState: project.approvalState,
lightDispatchReminderEnabled: Boolean(project.lightDispatchReminderEnabled),
};
}
@@ -2783,6 +2786,7 @@ function normalizeProject(raw: Partial<Project>, fallback?: Project): Project {
createdByAgent: raw.createdByAgent ?? false,
collaborationMode: raw.collaborationMode ?? "development",
approvalState: raw.approvalState ?? "not_required",
lightDispatchReminderEnabled: raw.lightDispatchReminderEnabled ?? false,
orchestrationBackendOverride: normalizeOrchestrationBackendOverride(raw.orchestrationBackendOverride),
agentControls: normalizeProjectAgentControls(raw.agentControls),
};
@@ -3686,6 +3690,33 @@ export async function updateProjectOrchestrationBackendOverride(input: {
});
}
export async function updateProjectLightDispatchReminder(input: {
projectId: string;
requestedBy: string;
lightDispatchReminderEnabled: boolean;
}) {
return mutateStateIfChanged((state) => {
const project = state.projects.find((item) => item.id === input.projectId);
if (!project) {
throw new Error("PROJECT_NOT_FOUND");
}
if (!project.isGroup) {
throw new Error("PROJECT_NOT_GROUP_CHAT");
}
requireDispatchActorSession(state, input.requestedBy);
const nextValue = Boolean(input.lightDispatchReminderEnabled);
if (Boolean(project.lightDispatchReminderEnabled) == nextValue) {
return { result: project, changed: false };
}
project.lightDispatchReminderEnabled = nextValue;
project.updatedAt = nowIso();
project.threadMeta.updatedAt = project.updatedAt;
return { result: project, changed: true };
});
}
export async function hasPersistedProject(projectId: string) {
const rawState = await loadPersistedStateRaw();
return Array.isArray(rawState.projects) && rawState.projects.some((project) => project?.id === projectId);
@@ -5559,6 +5590,7 @@ export async function confirmDispatchPlanAndCreateExecutions(input: {
planId: string;
confirmedBy: string;
approvedTargetProjectIds: string[];
rememberLightReminder?: boolean;
}) {
const result = await mutateState((state) => {
const groupProjectId = input.groupProjectId.trim();
@@ -5566,6 +5598,11 @@ export async function confirmDispatchPlanAndCreateExecutions(input: {
const groupProject = state.projects.find((item) => item.id === groupProjectId);
if (!groupProject) throw new Error("PROJECT_NOT_FOUND");
if (!canOwnDispatchPlans(groupProject)) throw new Error("PROJECT_NOT_GROUP_CHAT");
if (input.rememberLightReminder && !groupProject.lightDispatchReminderEnabled) {
groupProject.lightDispatchReminderEnabled = true;
groupProject.updatedAt = nowIso();
groupProject.threadMeta.updatedAt = groupProject.updatedAt;
}
const plan = applyDispatchPlanConfirmationInState(state, {
planId: input.planId,

View File

@@ -71,6 +71,29 @@ export function summarizeDispatchPlan(plan: DispatchPlanUiPayload | null | undef
return `${summary}\n推荐线程${titles.join("、")}`;
}
export function summarizeDispatchPlanCompact(plan: DispatchPlanUiPayload | null | undefined) {
if (!plan) {
return "主 Agent 暂未生成推荐线程。";
}
const summary = plan.summary?.trim() || "主 Agent 已生成推荐线程。";
const titles = (plan.targets ?? [])
.map((target) => target.threadDisplayName?.trim() || "")
.filter(Boolean);
if (!titles.length) {
return truncateDispatchSummary(summary);
}
return `推荐给:${titles.join("、")}\n${truncateDispatchSummary(summary)}`;
}
export function summarizeDispatchPlanLightTitle(plan: DispatchPlanUiPayload | null | undefined) {
const count = (plan?.targets ?? []).length;
return count > 0 ? `主 Agent 已推荐 ${count} 个线程` : "主 Agent 已推荐线程";
}
function truncateDispatchSummary(summary: string) {
return summary.length > 32 ? `${summary.slice(0, 32)}` : summary;
}
export function extractApprovedTargetProjectIds(plan: DispatchPlanUiPayload | null | undefined) {
return (plan?.targets ?? [])
.map((target) => target.projectId?.trim() || "")