feat(position-roundtable): add delivery rejection workflow

This commit is contained in:
fengxiangdebaozi committed 2026-07-21 20:16:52 +08:00
1 parent 2ca8a23102
commit 1cd99a5a90
9 files changed
+1422 -148

No files matched your search

@@ -30,6 +30,9 @@ export interface PositionRoundtableNode {
artifactManifest: Array<Record<string, unknown>>;
revision: number;
upstreamRevision: Record<string, unknown> | null;
rejectionCount: number;
lastRejection: Record<string, unknown> | null;
invalidatedBy: string | null;
createdAt?: string;
updatedAt?: string;
}
@@ -42,6 +45,8 @@ export interface PositionRoundtableSession {
chainSnapshot: Record<string, unknown> | null;
intentThreadId: string | null;
intentSnapshot: Record<string, unknown> | null;
summarySnapshot: Record<string, unknown> | null;
actionPlanSnapshot: Record<string, unknown> | null;
status: "intent_pending" | "active" | "completed" | "archived";
createdAt?: string;
updatedAt?: string;
@@ -62,6 +67,9 @@ interface ServerNode {
artifact_manifest?: Array<Record<string, unknown>>;
revision?: number;
upstream_revision?: Record<string, unknown> | null;
rejection_count?: number;
last_rejection?: Record<string, unknown> | null;
invalidated_by?: string | null;
created_at?: string;
updated_at?: string;
}
@@ -74,6 +82,8 @@ interface ServerSession {
chain_snapshot?: Record<string, unknown> | null;
intent_thread_id: string | null;
intent_snapshot?: Record<string, unknown> | null;
summary_snapshot?: Record<string, unknown> | null;
action_plan_snapshot?: Record<string, unknown> | null;
status: PositionRoundtableSession["status"];
created_at?: string;
updated_at?: string;
@@ -105,6 +115,9 @@ function toNode(node: ServerNode): PositionRoundtableNode {
artifactManifest: node.artifact_manifest ?? [],
revision: node.revision ?? 0,
upstreamRevision: node.upstream_revision ?? null,
rejectionCount: node.rejection_count ?? 0,
lastRejection: node.last_rejection ?? null,
invalidatedBy: node.invalidated_by ?? null,
createdAt: node.created_at,
updatedAt: node.updated_at,
};
@@ -119,6 +132,8 @@ function toSession(session: ServerSession): PositionRoundtableSession {
chainSnapshot: session.chain_snapshot ?? null,
intentThreadId: session.intent_thread_id,
intentSnapshot: session.intent_snapshot ?? null,
summarySnapshot: session.summary_snapshot ?? null,
actionPlanSnapshot: session.action_plan_snapshot ?? null,
status: session.status,
createdAt: session.created_at,
updatedAt: session.updated_at,
@@ -263,3 +278,45 @@ export async function completePositionNodeTurn(
);
return toNode(result);
}
export async function rejectPositionNode(
sessionId: string,
nodeKey: string,
input: { title: string; reason: string },
): Promise<PositionRoundtableSession> {
const result = await readJson<ServerSession>(
await apiFetch(
`${BASE()}/sessions/${encodeURIComponent(sessionId)}/nodes/${encodeURIComponent(nodeKey)}/reject`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: input.title,
reason: input.reason,
}),
},
),
"reject position node",
);
return toSession(result);
}
export async function generatePositionSummary(sessionId: string): Promise<PositionRoundtableSession> {
const result = await readJson<ServerSession>(
await apiFetch(`${BASE()}/sessions/${encodeURIComponent(sessionId)}/summary/start`, {
method: "POST",
}),
"generate position summary",
);
return toSession(result);
}
export async function generatePositionActionPlan(sessionId: string): Promise<PositionRoundtableSession> {
const result = await readJson<ServerSession>(
await apiFetch(`${BASE()}/sessions/${encodeURIComponent(sessionId)}/action-plan/start`, {
method: "POST",
}),
"generate position action plan",
);
return toSession(result);
}
@@ -78,7 +78,8 @@ export function PositionNodeChat({
sessionStatus !== "archived" &&
node.positionId === currentPositionId &&
node.status !== "locked" &&
node.status !== "error";
node.status !== "error" &&
!node.invalidatedBy;
useEffect(() => {
setBoundThreadId(node.threadId);
@@ -152,6 +153,8 @@ export function PositionNodeChat({
toast.info(
sessionStatus === "archived"
? "该会话已归档,仅可查看历史记录"
: node.invalidatedBy
? "上游产物已被驳回或重做,当前节点需等待前序节点重新完成"
: node.status === "locked"
? "该节点尚未解锁"
: "当前岗位只能查看该节点对话",
@@ -181,6 +184,8 @@ export function PositionNodeChat({
const readOnlyHint =
sessionStatus === "archived"
? "该会话已归档,仅可查看历史对话和产物"
: node.invalidatedBy
? "上游产物已变更,需等待前序节点重新完成后再重做"
: node.status === "locked"
? "等待上游岗位完成后解锁"
: node.positionId !== currentPositionId
File diff suppressed because it is too large. Load diff