添加cadfs_to_cdsl代码,优化cad生成
This commit is contained in:
@@ -395,7 +395,9 @@ button:disabled {
|
||||
.studio-main { display: flex; min-height: 0; flex: 1; }
|
||||
.task-documents { border-top: 1px solid var(--ui-border); max-height: 34vh; overflow: auto; background: var(--ui-panel-bg); }
|
||||
.task-checklist { padding: 8px 12px; border-bottom: 1px solid var(--ui-border); display: grid; gap: 5px; }
|
||||
.task-checklist-item { display: grid; grid-template-columns: 48px minmax(0, 1fr); gap: 8px; font-size: 12px; line-height: 1.35; }
|
||||
.task-checklist-item { display: grid; grid-template-columns: 48px minmax(0, 1fr) auto; gap: 8px; font-size: 12px; line-height: 1.35; align-items: start; }
|
||||
.task-checklist-item small { display: block; color: var(--ui-muted); margin-top: 2px; overflow-wrap: anywhere; }
|
||||
.task-checklist-item button { min-height: 24px; padding: 2px 7px; font-size: 12px; }
|
||||
.task-checklist-item > span { color: var(--ui-muted); }
|
||||
.task-checklist-item.is-pass > span { color: #16784d; }
|
||||
.task-checklist-item.is-fail > span { color: #b73c32; }
|
||||
|
||||
@@ -561,7 +561,23 @@ function StudioShell({
|
||||
<div className="studio-main">
|
||||
<aside className="agent-pane">
|
||||
<AgentThread attachments={attachments} uploading={uploading} uploadError={uploadError} taskRunning={taskRunning} onUpload={onUpload} onCancel={onCancel} />
|
||||
<TaskDocuments task={taskRecord} />
|
||||
<TaskDocuments task={taskRecord} onSelectRevision={(revisionId) => {
|
||||
const revision = taskRecord?.revisions.find((item) => item.revision_id === revisionId);
|
||||
if (!revision?.cdsl_path || !revision.step_path || !revision.glb_path || !revision.report_path || !taskRecord) return;
|
||||
onCadResult({
|
||||
taskId: taskRecord.task_id,
|
||||
revisionId,
|
||||
cdslPath: revision.cdsl_path,
|
||||
stepPath: revision.step_path,
|
||||
glbPath: revision.glb_path,
|
||||
reportPath: revision.report_path,
|
||||
summary: revision.summary || "CDSL CAD model",
|
||||
referenceIds: revision.reference_ids || [],
|
||||
engine: revision.engine || "cdsl_only",
|
||||
checkpoint: revision.visibility === "checkpoint",
|
||||
lifecycle: taskRecord.lifecycle || "running",
|
||||
});
|
||||
}} />
|
||||
</aside>
|
||||
<section className="preview-pane">
|
||||
<CadViewerPreview result={cadResult} isGenerating={running} lastError={lastError} theme={theme} onError={handleViewerError} onSelectionChange={onSelectionChange} />
|
||||
@@ -571,17 +587,26 @@ function StudioShell({
|
||||
);
|
||||
}
|
||||
|
||||
function TaskDocuments({ task }: { task: TaskRecord | null }) {
|
||||
function TaskDocuments({ task, onSelectRevision }: { task: TaskRecord | null; onSelectRevision: (revisionId: string) => void }) {
|
||||
const documents = [
|
||||
["需求文档", task?.requirements_markdown],
|
||||
["完成目标", task?.completion_target_markdown],
|
||||
["建模计划", task?.modeling_plan_markdown],
|
||||
] as const;
|
||||
if (!documents.some(([, markdown]) => markdown)) return null;
|
||||
if (!documents.some(([, markdown]) => markdown) && !task?.feature_nodes?.length) return null;
|
||||
return <section className="task-documents" aria-label="任务文档">
|
||||
{task?.checklist_progress?.length ? <div className="task-checklist" aria-label="验收进度">
|
||||
{task.checklist_progress.map((item) => <div key={item.requirement_id || item.statement} className={`task-checklist-item is-${item.status}`}><span>{item.status === "pass" ? "完成" : item.status === "fail" ? "未通过" : "待验证"}</span>{item.statement}</div>)}
|
||||
</div> : null}
|
||||
{task?.feature_nodes?.length ? <details open className="task-document" aria-label="特征 DAG">
|
||||
<summary>特征 DAG</summary>
|
||||
<div className="task-checklist">
|
||||
{task.feature_nodes.slice().sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)).map((node) => <div key={node.node_id} className={`task-checklist-item is-${node.status || "pending"}`}>
|
||||
<span>{node.status === "done" ? "完成" : node.status === "running" ? "执行中" : node.status === "failed" ? "失败" : node.status === "blocked" ? "阻塞" : "待执行"}</span>
|
||||
<div><strong>{node.intent || node.node_id}</strong><small>{node.atomic_id} · 优先级 {node.priority}{node.depends_on?.length ? ` · 依赖 ${node.depends_on.join(", ")}` : ""}{node.attempt ? ` · 尝试 ${node.attempt}` : ""}</small>{node.error ? <small>{node.error}</small> : null}</div>
|
||||
{node.status === "done" && node.revision_id ? <button type="button" title="查看此特征检查点" onClick={() => onSelectRevision(node.revision_id!)}>查看</button> : null}
|
||||
</div>)}
|
||||
</div>
|
||||
</details> : null}
|
||||
{documents.map(([title, markdown]) => markdown ? <details key={title} className="task-document"><summary>{title}</summary><MarkdownDocument>{markdown}</MarkdownDocument></details> : null)}
|
||||
</section>;
|
||||
}
|
||||
|
||||
@@ -44,9 +44,10 @@ export function activeCheckpointPreview(task: TaskRecord | null): CadResult | nu
|
||||
|
||||
export function latestSuccessfulResult(task: TaskRecord | null): CadResult | null {
|
||||
if (!task) return null;
|
||||
// Checkpoints are intentionally private after a failed run. Returning one
|
||||
// here makes the restored viewer request an artifact the backend denies.
|
||||
if (task.lifecycle === "failed" && !task.published_revision) return null;
|
||||
// v3.2 deliberately exposes its last verified checkpoint on a failed DAG:
|
||||
// failure means requirements were not completed, not that earlier geometry
|
||||
// should disappear. Legacy task projections retain the former policy.
|
||||
if (task.lifecycle === "failed" && !task.published_revision && task.schema_version !== "3.2") return null;
|
||||
const current =
|
||||
task.revisions.find((revision) => revision.revision_id === (task.published_revision || task.current_revision)) ??
|
||||
[...task.revisions].reverse().find((revision) => revision.status === "success" && revision.visibility !== "checkpoint");
|
||||
|
||||
@@ -180,6 +180,21 @@ test("does not restore a private checkpoint after a failed run", () => {
|
||||
assert.equal(result, null);
|
||||
});
|
||||
|
||||
test("restores the last verified v3.2 DAG checkpoint after a failed run", () => {
|
||||
const result = latestSuccessfulResult({
|
||||
schema_version: "3.2",
|
||||
task_id: "cad_abc",
|
||||
current_revision: "rev_002",
|
||||
active_revision: "rev_002",
|
||||
lifecycle: "failed",
|
||||
revisions: [
|
||||
{ revision_id: "rev_002", status: "success", visibility: "checkpoint", cdsl_path: "aa", step_path: "bb", glb_path: "cc", report_path: "dd" },
|
||||
],
|
||||
});
|
||||
assert.equal(result?.revisionId, "rev_002");
|
||||
assert.equal(result?.checkpoint, true);
|
||||
});
|
||||
|
||||
test("restores an active checkpoint only while the task is running", () => {
|
||||
const result = activeCheckpointPreview({
|
||||
task_id: "cad_abc", current_revision: "rev_002", active_revision: "rev_002", published_revision: "rev_001", lifecycle: "running",
|
||||
|
||||
@@ -124,8 +124,32 @@ export type TaskRecord = {
|
||||
requirements_document_path?: string;
|
||||
completion_target_markdown?: string | null;
|
||||
completion_target_path?: string;
|
||||
modeling_plan_markdown?: string | null;
|
||||
modeling_plan_path?: string;
|
||||
feature_plan?: {
|
||||
schema_version?: string;
|
||||
parent_plan_hash?: string;
|
||||
replaces_node_ids?: string[];
|
||||
nodes?: Array<Record<string, unknown>>;
|
||||
final_claim_ids?: string[];
|
||||
} | null;
|
||||
feature_plan_path?: string;
|
||||
feature_plan_hash?: string;
|
||||
current_feature_node_id?: string;
|
||||
pending_feature?: { action_id: string; node_id: string; plan_hash: string; atomic_id: string; claim_ids: string[]; depends_on_node_ids: string[] } | null;
|
||||
feature_nodes?: Array<{
|
||||
node_id: string;
|
||||
intent?: string;
|
||||
atomic_id?: string;
|
||||
priority?: number;
|
||||
depends_on?: string[];
|
||||
claim_ids?: string[];
|
||||
status?: "pending" | "ready" | "running" | "done" | "failed" | "blocked" | "invalidated" | string;
|
||||
attempt?: number;
|
||||
failure_class?: string;
|
||||
error?: string;
|
||||
revision_id?: string;
|
||||
feature_id?: string;
|
||||
evidence?: Array<Record<string, unknown>>;
|
||||
}>;
|
||||
completion_result_markdown?: string | null;
|
||||
completion_result_path?: string;
|
||||
claim_summary?: Array<{
|
||||
|
||||
Reference in New Issue
Block a user