chore: save current work

This commit is contained in:
2026-09-01 16:37:27 +08:00
parent bc87bd6d2d
commit 97a03c290b
24 changed files with 1380 additions and 5073 deletions
+2 -12
View File
@@ -18,8 +18,7 @@ export function CadProgressPart({ data }: { data: CadProgress }) {
const statusLabel = isRunning ? "进行中" : isWaiting ? data.lifecycle === "waiting_retry" ? "等待重试" : "等待确认" : isError ? "失败" : status === "success" ? "完成" : data.status;
const Icon = data.step === "tool_call" ? Wrench : data.step.includes("review") || data.step === "final_review" ? Eye : data.step === "rollback" ? RotateCcw : data.step.includes("requirements") || data.step.includes("checklist") ? FileCheck : data.step.includes("diagnostic") ? Search : isError || isWaiting ? AlertTriangle : Check;
const evidence = data.evidence || (Array.isArray(data.review?.evidence) ? data.review.evidence.map(String) : []);
const documentTitle = data.step === "requirements_review" ? "需求合同复核" : "";
const documentMarkdown = data.step === "requirements_document" ? withoutRequirementsFilename(data.markdown || "") : data.markdown || "";
const documentMarkdown = data.markdown || "";
return (
<div className={`cad-message cad-progress${isError ? " is-error" : ""}${isWaiting ? " is-waiting" : ""}`} role="status" aria-live="polite">
<div className="cad-message-heading">
@@ -32,8 +31,7 @@ export function CadProgressPart({ data }: { data: CadProgress }) {
{data.questions?.length ? <ul className="cad-waiting-questions">{data.questions.map((question, index) => <li key={`${question}-${index}`}>{question}</li>)}</ul> : null}
{data.issues?.length ? <ul className="cad-waiting-questions">{data.issues.map((issue, index) => <li key={`${issue}-${index}`}>{issue}</li>)}</ul> : null}
{data.verificationWarnings?.length ? <details className="cad-event-details" open><summary> ({data.verificationWarnings.length})</summary><ul>{data.verificationWarnings.map((warning, index) => <li key={`${warning}-${index}`}>{warning}</li>)}</ul></details> : null}
{data.appliedNormalizations?.length ? <details className="cad-event-details"><summary> ({data.appliedNormalizations.length})</summary><JsonTree data={data.appliedNormalizations} /></details> : null}
{documentMarkdown ? <details className="cad-event-details cad-document-details" open={data.step === "requirements_document"}><summary>{documentTitle || "文档内容"}</summary><MarkdownDocument>{documentMarkdown}</MarkdownDocument></details> : null}
{documentMarkdown ? <details className="cad-event-details cad-document-details"><summary></summary><MarkdownDocument>{documentMarkdown}</MarkdownDocument></details> : null}
{data.arguments ? <details className="cad-event-details"><summary></summary><JsonTree data={data.arguments} /></details> : null}
{data.result !== undefined ? <details className="cad-event-details"><summary></summary><JsonTree data={data.result} /></details> : null}
{evidence.length ? <details className="cad-event-details"><summary> ({evidence.length})</summary><ul>{evidence.map((item, index) => <li key={`${item}-${index}`}>{item}</li>)}</ul></details> : null}
@@ -41,13 +39,6 @@ export function CadProgressPart({ data }: { data: CadProgress }) {
);
}
function withoutRequirementsFilename(markdown: string) {
return markdown
.replace(/^\s*#{1,6}\s*`?requirements\.md`?\s*\n+/i, "")
.replace(/^\s*`?requirements\.md`?\s*\n+/i, "")
.trimStart();
}
export function CadResultPart({ data }: { data: CadResult }) {
const downloads: Array<[string, string]> = data.checkpoint ? [] : [
["STEP", data.stepPath],
@@ -69,7 +60,6 @@ export function CadResultPart({ data }: { data: CadResult }) {
</div>
{data.referenceIds.length ? <div className="cad-result-notes"><strong></strong><span>{data.referenceIds.join("")}</span></div> : null}
{data.verificationWarnings?.length ? <div className="cad-result-notes"><strong></strong><span>{data.verificationWarnings.join("")}</span></div> : null}
{data.appliedNormalizations?.length ? <details className="cad-event-details"><summary> ({data.appliedNormalizations.length})</summary><JsonTree data={data.appliedNormalizations} /></details> : null}
{downloads.length ? <div className="download-row">
{downloads.map(([label, path]) => (
<a key={label} className="download-link" href={encodeArtifactUrl(data.taskId, path)} download aria-label={`下载 ${label}`}>
-1
View File
@@ -32,7 +32,6 @@ function resultForRevision(task: TaskRecord, revisionId: string, checkpoint: boo
lifecycle: task.lifecycle || "completed",
verificationStatus: task.verification_status,
verificationWarnings: task.verification_warnings || [],
appliedNormalizations: task.applied_normalizations || [],
};
}
-1
View File
@@ -77,7 +77,6 @@ export function restoreTaskProjection(messages: CadUIMessage[], task: TaskRecord
userActionRequired: Boolean(task.user_action_required),
verificationStatus: task.verification_status,
verificationWarnings: task.verification_warnings || [],
appliedNormalizations: task.applied_normalizations || [],
};
return [...messages, {
id: `projection_${task.task_id}_${task.state_version || 0}`,
+9 -9
View File
@@ -46,7 +46,7 @@ test("keeps terminal schema field errors visible to the CAD error part", () => {
event: "cad_error",
data: {
stage: "generation",
tool: "patch_requirements_draft",
tool: "submit_requirements_spec",
message: "Author repeatedly failed the schema.",
fieldErrors: [{ path: "/patches", message: "Field required" }],
},
@@ -54,7 +54,7 @@ test("keeps terminal schema field errors visible to the CAD error part", () => {
assert.equal(chunk?.type, "data-cad-error");
assert.deepEqual("data" in chunk! ? chunk.data : null, {
stage: "generation",
tool: "patch_requirements_draft",
tool: "submit_requirements_spec",
message: "Author repeatedly failed the schema.",
fieldErrors: [{ path: "/patches", message: "Field required" }],
});
@@ -69,7 +69,7 @@ test("maps a waiting terminal into a visible user-decision state", () => {
lifecycle: "waiting_for_user",
message: "Requirements need a user decision.",
questions: [question],
reviewPath: "documents/requirements-review.json",
clarificationPath: "documents/requirements-clarification.json",
},
}, "text_1");
assert.equal(chunk?.type, "data-cad-progress");
@@ -81,7 +81,7 @@ test("maps a waiting terminal into a visible user-decision state", () => {
taskId: "cad_abc",
lifecycle: "waiting_for_user",
questions: [question],
reviewPath: "documents/requirements-review.json",
clarificationPath: "documents/requirements-clarification.json",
});
});
@@ -90,7 +90,7 @@ test("restores a complete waiting terminal from the task projection", () => {
task_id: "cad_abc", current_revision: "", lifecycle: "waiting_for_user", phase: "WAITING_FOR_USER",
state_version: 7, message: "A decision is required.", questions: ["Four holes or six?"],
blocker_type: "requirements_ambiguity", user_action_required: true,
verification_status: "verified", verification_warnings: [], applied_normalizations: [], revisions: [],
verification_status: "pending", verification_warnings: [], revisions: [],
});
const part = restored[0].parts[0];
assert.equal(part.type, "data-cad-progress");
@@ -101,14 +101,14 @@ test("restores a complete waiting terminal from the task projection", () => {
}
});
test("keeps unmet review issues visible when requirements review cannot converge", () => {
const issue = "The counterbores need a feature-scoped front-side claim.";
test("keeps explicit runtime issues visible when generation stops", () => {
const issue = "The selected host face is unavailable.";
const chunk = backendEventToUiChunk({
event: "task_terminal",
data: {
taskId: "cad_abc",
lifecycle: "waiting_for_user",
message: "Requirements review did not converge.",
message: "Runtime validation stopped generation.",
issues: [issue],
},
}, "text_1");
@@ -117,7 +117,7 @@ test("keeps unmet review issues visible when requirements review cannot converge
step: "task_terminal",
label: "生成任务",
status: "waiting",
message: "Requirements review did not converge.",
message: "Runtime validation stopped generation.",
taskId: "cad_abc",
lifecycle: "waiting_for_user",
issues: [issue],
+3 -5
View File
@@ -20,7 +20,7 @@ export function backendEventToUiChunk(
data: { ...item.data, sequence },
};
}
if (["requirements_review", "action_selection", "tool_call", "candidate_result", "candidate_review", "final_review", "task_terminal"].includes(item.event)) {
if (["image_observation", "requirements_ready", "completion_result_ready", "action_selection", "tool_call", "candidate_result", "candidate_review", "final_review", "task_terminal"].includes(item.event)) {
const review = item.data.review && typeof item.data.review === "object"
? item.data.review as Record<string, unknown>
: null;
@@ -44,7 +44,7 @@ export function backendEventToUiChunk(
type: "data-cad-progress",
id: `event_${eventId}`,
data: { step: item.event, label: ({
requirements_review: "需求合同独立复核", action_selection: "动作选择", tool_call: "建模工具", candidate_result: "候选构建", candidate_review: "候选独立复核", final_review: "最终独立复核", task_terminal: "生成任务",
image_observation: "参考图片观察", requirements_ready: "需求规格已就绪", completion_result_ready: "完成结果已就绪", action_selection: "动作选择", tool_call: "建模工具", candidate_result: "候选构建", candidate_review: "候选独立复核", final_review: "最终独立复核", task_terminal: "生成任务",
} as Record<string, string>)[item.event], status, ...metadata, message: String(
item.data.message || item.data.reason
|| (Array.isArray(item.data.questions) ? item.data.questions.map(String).filter(Boolean).join("") : "")
@@ -56,13 +56,11 @@ export function backendEventToUiChunk(
...(item.data.lifecycle ? { lifecycle: String(item.data.lifecycle) } : {}),
...(Array.isArray(item.data.questions) ? { questions: item.data.questions.map(String).filter(Boolean) } : {}),
...(Array.isArray(item.data.issues) ? { issues: item.data.issues.map(String).filter(Boolean) } : {}),
...(Array.isArray(item.data.unresolved) ? { unresolved: item.data.unresolved } : {}),
...(item.data.blockerType ? { blockerType: String(item.data.blockerType) } : {}),
...(typeof item.data.userActionRequired === "boolean" ? { userActionRequired: item.data.userActionRequired } : {}),
...(item.data.verificationStatus ? { verificationStatus: String(item.data.verificationStatus) } : {}),
...(Array.isArray(item.data.verificationWarnings) ? { verificationWarnings: item.data.verificationWarnings.map(String).filter(Boolean) } : {}),
...(Array.isArray(item.data.appliedNormalizations) ? { appliedNormalizations: item.data.appliedNormalizations } : {}),
...(item.data.reviewPath ? { reviewPath: String(item.data.reviewPath) } : {}),
...(item.data.clarificationPath ? { clarificationPath: String(item.data.clarificationPath) } : {}),
...(item.data.timestamp ? { timestamp: String(item.data.timestamp) } : {}),
...(item.data.markdown ? { markdown: String(item.data.markdown) } : {}),
...(item.data.tool ? { tool: String(item.data.tool) } : {}),
+8 -10
View File
@@ -18,14 +18,12 @@ export type CadProgress = {
evidence?: string[];
questions?: string[];
issues?: string[];
unresolved?: Array<{ draftId?: string; reasonCode?: string; question?: string }>;
blockerType?: string;
userActionRequired?: boolean;
verificationStatus?: "verified" | "completed_with_risks" | string;
verificationWarnings?: string[];
appliedNormalizations?: Array<Record<string, unknown>>;
review?: Record<string, unknown>;
reviewPath?: string;
clarificationPath?: string;
lifecycle?: "running" | "completed" | "failed" | "waiting_retry" | "waiting_for_user" | string;
attempt?: number;
maxAttempts?: number;
@@ -47,7 +45,6 @@ export type CadResult = {
lifecycle?: "running" | "completed" | "failed" | string;
verificationStatus?: "verified" | "completed_with_risks" | string;
verificationWarnings?: string[];
appliedNormalizations?: Array<Record<string, unknown>>;
};
export type CadError = {
@@ -118,14 +115,16 @@ export type TaskRecord = {
phase?: string;
state_version?: number;
active_candidate_id?: string;
requirements_draft?: Record<string, unknown> | null;
requirements_draft_path?: string;
requirements_review?: Record<string, unknown> | null;
requirements_review_path?: string;
requirements_spec?: Record<string, unknown> | null;
requirements_spec_path?: string;
clarification_path?: string;
requirements_contract?: Record<string, unknown> | null;
requirements_contract_path?: string;
requirements_markdown?: string | null;
completion_markdown?: string | null;
completion_target_markdown?: string | null;
completion_target_path?: string;
completion_result_markdown?: string | null;
completion_result_path?: string;
claim_summary?: Array<{
requirement_id: string;
claim_id: string;
@@ -145,7 +144,6 @@ export type TaskRecord = {
user_action_required?: boolean;
verification_status?: "verified" | "completed_with_risks" | string;
verification_warnings?: string[];
applied_normalizations?: Array<Record<string, unknown>>;
revisions: TaskRevision[];
};