wip: preserve local engine and agent workflow changes before ganjihong refactor integration
This commit is contained in:
@@ -21,7 +21,7 @@ import type {
|
||||
} from "@/lib/cad-types";
|
||||
import { AgentThread } from "./agent-thread";
|
||||
import { CadViewerPreview } from "./cad-viewer-preview";
|
||||
import { MarkdownDocument } from "./rich-content";
|
||||
import { JsonTree, MarkdownDocument } from "./rich-content";
|
||||
import type { AssistantRuntime } from "@assistant-ui/react";
|
||||
|
||||
type LoadState = "loading" | "ready" | "error";
|
||||
@@ -557,27 +557,10 @@ function StudioShell({
|
||||
</div>
|
||||
</header>
|
||||
{!config?.configured ? <div className="config-warning"><AlertCircle size={16} /><span>未配置模型环境变量,聊天会保留诊断但不会生成虚假模型。</span></div> : null}
|
||||
{config?.autonomous_generation && !config.review_configured ? <div className="config-warning"><AlertCircle size={16} /><span>最终视觉复核未配置,任务在最终发布前会停止:{config.review_error || "请配置独立视觉模型。"}</span></div> : null}
|
||||
<div className="studio-main">
|
||||
<aside className="agent-pane">
|
||||
<AgentThread attachments={attachments} uploading={uploading} uploadError={uploadError} taskRunning={taskRunning} onUpload={onUpload} onCancel={onCancel} />
|
||||
<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",
|
||||
});
|
||||
}} />
|
||||
<TaskDocuments task={taskRecord} />
|
||||
</aside>
|
||||
<section className="preview-pane">
|
||||
<CadViewerPreview result={cadResult} isGenerating={running} lastError={lastError} theme={theme} onError={handleViewerError} onSelectionChange={onSelectionChange} />
|
||||
@@ -587,27 +570,18 @@ function StudioShell({
|
||||
);
|
||||
}
|
||||
|
||||
function TaskDocuments({ task, onSelectRevision }: { task: TaskRecord | null; onSelectRevision: (revisionId: string) => void }) {
|
||||
const documents = [
|
||||
["需求文档", task?.requirements_markdown],
|
||||
["完成目标", task?.completion_target_markdown],
|
||||
function TaskDocuments({ task }: { task: TaskRecord | null }) {
|
||||
const structured = [
|
||||
["需求分析", task?.requirements_analysis],
|
||||
["Authoring CDSL", task?.authoring_cdsl],
|
||||
["编译审计", task?.compile_audit],
|
||||
["构建诊断", task?.diagnostics],
|
||||
] as const;
|
||||
if (!documents.some(([, markdown]) => markdown) && !task?.feature_nodes?.length) return null;
|
||||
if (!structured.some(([, value]) => value) && !task?.completion_result_markdown) 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)}
|
||||
{task?.repair_count !== undefined ? <div className="task-checklist"><div className="task-checklist-item"><span>修复</span><div>{task.repair_count} / {task.repair_budget ?? 2}</div></div></div> : null}
|
||||
{structured.map(([title, value]) => value ? <details key={title} className="task-document"><summary>{title}</summary><JsonTree data={value} /></details> : null)}
|
||||
{task?.completion_result_markdown ? <details className="task-document" open><summary>完成报告</summary><MarkdownDocument>{task.completion_result_markdown}</MarkdownDocument></details> : null}
|
||||
</section>;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { AlertTriangle, Box, Check, Download, Eye, FileCheck, Loader2, RotateCcw, Search, Wrench } from "lucide-react";
|
||||
import { AlertTriangle, Box, Check, Download, FileCheck, Loader2, RotateCcw, Search } from "lucide-react";
|
||||
import { encodeArtifactUrl } from "@/lib/cad-artifacts";
|
||||
import type { CadError, CadProgress, CadResult } from "@/lib/cad-types";
|
||||
import { JsonTree, MarkdownDocument } from "./rich-content";
|
||||
import { MarkdownDocument } from "./rich-content";
|
||||
|
||||
export function TextPart({ text }: { text: string }) {
|
||||
if (!text.trim()) return null;
|
||||
@@ -15,26 +15,20 @@ export function CadProgressPart({ data }: { data: CadProgress }) {
|
||||
const isRunning = status === "running";
|
||||
const isError = status === "error";
|
||||
const isWaiting = status === "waiting";
|
||||
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 statusLabel = isRunning ? "进行中" : isWaiting ? "等待确认" : isError ? "失败" : status === "success" ? "完成" : data.status;
|
||||
const Icon = data.step === "repair_started" ? RotateCcw : data.step === "build_result" ? Box : data.step === "cdsl_compiled" ? Search : data.step === "requirements_ready" || data.step === "authoring_cdsl_ready" ? FileCheck : isError || isWaiting ? AlertTriangle : Check;
|
||||
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">
|
||||
{isRunning ? <Loader2 className="spin" size={14} aria-hidden="true" /> : <Icon size={14} aria-hidden="true" />}
|
||||
<span>{data.label || data.step}</span>
|
||||
{data.tool ? <code className="cad-tool-name">{data.tool}</code> : null}
|
||||
<span className="cad-status-label">{statusLabel}</span>
|
||||
</div>
|
||||
{data.message ? <div className="cad-message-copy">{data.message}</div> : null}
|
||||
{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}
|
||||
{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}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -59,7 +53,6 @@ export function CadResultPart({ data }: { data: CadResult }) {
|
||||
<span>{data.referenceIds.length} 个参考</span>
|
||||
</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}
|
||||
{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}`}>
|
||||
@@ -84,7 +77,6 @@ export function CadErrorPart({ data }: { data: CadError }) {
|
||||
<div className="cad-message cad-error" role="alert">
|
||||
<div className="cad-message-heading"><AlertTriangle size={14} aria-hidden="true" /><span>{stage}失败</span></div>
|
||||
<div className="cad-message-copy">{data.message}</div>
|
||||
{data.tool ? <code className="cad-tool-name">{data.tool}</code> : null}
|
||||
{data.fieldErrors?.length ? <details className="cad-event-details" open><summary>字段错误 ({data.fieldErrors.length})</summary><ul>{data.fieldErrors.map((error, index) => <li key={`${error.path || "field"}-${index}`}><code>{error.path || "/"}</code>{error.message ? `: ${error.message}` : ""}</li>)}</ul></details> : null}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -30,8 +30,6 @@ function resultForRevision(task: TaskRecord, revisionId: string, checkpoint: boo
|
||||
engine: current.engine || "cdsl_only",
|
||||
checkpoint,
|
||||
lifecycle: task.lifecycle || "completed",
|
||||
verificationStatus: task.verification_status,
|
||||
verificationWarnings: task.verification_warnings || [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,10 +42,7 @@ export function activeCheckpointPreview(task: TaskRecord | null): CadResult | nu
|
||||
|
||||
export function latestSuccessfulResult(task: TaskRecord | null): CadResult | null {
|
||||
if (!task) 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;
|
||||
if (task.lifecycle === "failed" && !task.published_revision) 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");
|
||||
|
||||
@@ -62,7 +62,7 @@ export function restoreTaskProjection(messages: CadUIMessage[], task: TaskRecord
|
||||
));
|
||||
if (alreadyVisible) return messages;
|
||||
const status = task.lifecycle === "failed" ? "error"
|
||||
: task.lifecycle === "waiting_for_user" || task.lifecycle === "waiting_retry" ? "waiting"
|
||||
: task.lifecycle === "waiting_for_user" ? "waiting"
|
||||
: task.lifecycle === "completed" ? "success" : "running";
|
||||
const progress: CadProgress = {
|
||||
step,
|
||||
@@ -73,10 +73,7 @@ export function restoreTaskProjection(messages: CadUIMessage[], task: TaskRecord
|
||||
message: task.message || (terminal ? "CAD 任务已停止。" : "CAD 任务正在运行。"),
|
||||
questions: task.questions || [],
|
||||
issues: task.issues || [],
|
||||
blockerType: task.blocker_type,
|
||||
userActionRequired: Boolean(task.user_action_required),
|
||||
verificationStatus: task.verification_status,
|
||||
verificationWarnings: task.verification_warnings || [],
|
||||
};
|
||||
return [...messages, {
|
||||
id: `projection_${task.task_id}_${task.state_version || 0}`,
|
||||
|
||||
@@ -9,10 +9,18 @@ import type { CadUIMessage } from "./cad-types";
|
||||
test("maps backend cad_result SSE into an AI SDK data part", () => {
|
||||
const chunk = backendEventToUiChunk({
|
||||
event: "cad_result",
|
||||
data: { taskId: "cad_abc", revisionId: "rev_001" },
|
||||
data: {
|
||||
taskId: "cad_abc", revisionId: "rev_001", cdslPath: "model.cdsl.json",
|
||||
stepPath: "model.step", glbPath: "model.glb", reportPath: "rebuild-report.json",
|
||||
summary: "plate", referenceIds: [], engine: "cdsl_only",
|
||||
},
|
||||
}, "text_1");
|
||||
assert.equal(chunk?.type, "data-cad-result");
|
||||
assert.deepEqual("data" in chunk! ? chunk.data : null, { taskId: "cad_abc", revisionId: "rev_001" });
|
||||
assert.deepEqual("data" in chunk! ? chunk.data : null, {
|
||||
taskId: "cad_abc", revisionId: "rev_001", cdslPath: "model.cdsl.json",
|
||||
stepPath: "model.step", glbPath: "model.glb", reportPath: "rebuild-report.json",
|
||||
summary: "plate", referenceIds: [], engine: "cdsl_only",
|
||||
});
|
||||
});
|
||||
|
||||
test("keeps progressive revisions as separate data parts", () => {
|
||||
@@ -21,23 +29,13 @@ test("keeps progressive revisions as separate data parts", () => {
|
||||
assert.notEqual(first?.id, second?.id);
|
||||
});
|
||||
|
||||
test("maps final repair review into a blocking progress state", () => {
|
||||
test("maps a single-stage build repair into a blocking progress state", () => {
|
||||
const chunk = backendEventToUiChunk({
|
||||
event: "final_review", data: { taskId: "cad_abc", result: { status: "repair", evidence: ["missing round"] } },
|
||||
event: "build_result", data: { taskId: "cad_abc", status: "repair_required", message: "host face is ambiguous" },
|
||||
}, "text_1");
|
||||
assert.equal(chunk?.type, "data-cad-progress");
|
||||
assert.deepEqual("data" in chunk! ? chunk.data : null, {
|
||||
step: "final_review", label: "最终独立复核", status: "error", message: "", taskId: "cad_abc", result: { status: "repair", evidence: ["missing round"] },
|
||||
});
|
||||
});
|
||||
|
||||
test("maps a rejected independent candidate review into a blocking progress state", () => {
|
||||
const chunk = backendEventToUiChunk({
|
||||
event: "candidate_review", data: { taskId: "cad_abc", result: { status: "rejected", evidence: ["base is disconnected"] } },
|
||||
}, "text_1");
|
||||
assert.equal(chunk?.type, "data-cad-progress");
|
||||
assert.deepEqual("data" in chunk! ? chunk.data : null, {
|
||||
step: "candidate_review", label: "候选独立复核", status: "error", message: "", taskId: "cad_abc", result: { status: "rejected", evidence: ["base is disconnected"] },
|
||||
step: "build_result", label: "CAD 构建", status: "error", message: "host face is ambiguous", taskId: "cad_abc",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,7 +44,7 @@ test("keeps terminal schema field errors visible to the CAD error part", () => {
|
||||
event: "cad_error",
|
||||
data: {
|
||||
stage: "generation",
|
||||
tool: "compile_requirements_spec",
|
||||
tool: "write_authoring_cdsl",
|
||||
message: "Author repeatedly failed the schema.",
|
||||
fieldErrors: [{ path: "/patches", message: "Field required" }],
|
||||
},
|
||||
@@ -54,7 +52,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: "compile_requirements_spec",
|
||||
tool: "write_authoring_cdsl",
|
||||
message: "Author repeatedly failed the schema.",
|
||||
fieldErrors: [{ path: "/patches", message: "Field required" }],
|
||||
});
|
||||
@@ -124,17 +122,17 @@ test("keeps explicit runtime issues visible when generation stops", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("gives repeated tool events unique ordered parts", () => {
|
||||
const first = backendEventToUiChunk({ event: "tool_call", data: { taskId: "cad_abc", tool: "inspect_model", status: "running" } }, "text_1", 4);
|
||||
const second = backendEventToUiChunk({ event: "tool_call", data: { taskId: "cad_abc", tool: "inspect_model", status: "success" } }, "text_1", 5);
|
||||
test("gives repeated build events unique ordered parts", () => {
|
||||
const first = backendEventToUiChunk({ event: "build_result", data: { taskId: "cad_abc", status: "repair_required" } }, "text_1", 4);
|
||||
const second = backendEventToUiChunk({ event: "build_result", data: { taskId: "cad_abc", status: "completed" } }, "text_1", 5);
|
||||
assert.notEqual(first?.id, second?.id);
|
||||
assert.equal("data" in first! ? (first.data as { sequence?: number }).sequence : null, 4);
|
||||
assert.equal("data" in second! ? (second.data as { sequence?: number }).sequence : null, 5);
|
||||
});
|
||||
|
||||
test("reuses an invocation id so tool completion updates its running card", () => {
|
||||
const running = backendEventToUiChunk({ event: "tool_call", data: { taskId: "cad_abc", eventId: "call_1", invocationId: "call_1", tool: "submit_cdsl_fragment", status: "running" } }, "text_1", 4);
|
||||
const complete = backendEventToUiChunk({ event: "tool_call", data: { taskId: "cad_abc", eventId: "call_1", invocationId: "call_1", tool: "submit_cdsl_fragment", status: "success" } }, "text_1", 5);
|
||||
test("reuses an event id for build card updates", () => {
|
||||
const running = backendEventToUiChunk({ event: "build_result", data: { taskId: "cad_abc", eventId: "build_1", status: "repair_required" } }, "text_1", 4);
|
||||
const complete = backendEventToUiChunk({ event: "build_result", data: { taskId: "cad_abc", eventId: "build_1", status: "completed" } }, "text_1", 5);
|
||||
assert.equal(running?.id, complete?.id);
|
||||
});
|
||||
|
||||
@@ -180,21 +178,6 @@ 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",
|
||||
|
||||
@@ -20,15 +20,11 @@ export function backendEventToUiChunk(
|
||||
data: { ...item.data, sequence },
|
||||
};
|
||||
}
|
||||
if (["image_observation", "requirements_document_ready", "completion_target_ready", "requirements_compiled", "modeling_plan_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;
|
||||
if (["requirements_ready", "authoring_cdsl_ready", "cdsl_compiled", "build_result", "repair_started", "task_terminal"].includes(item.event)) {
|
||||
const lifecycle = String(item.data.lifecycle || "");
|
||||
const status = item.event === "task_terminal"
|
||||
? (lifecycle === "failed" ? "error" : lifecycle === "waiting_for_user" || lifecycle === "waiting_retry" ? "waiting" : "success")
|
||||
: String((item.data.result as Record<string, unknown> | undefined)?.status || "") === "rejected"
|
||||
|| String((item.data.result as Record<string, unknown> | undefined)?.status || "") === "repair"
|
||||
? (lifecycle === "failed" ? "error" : lifecycle === "waiting_for_user" ? "waiting" : "success")
|
||||
: String(item.data.status || "") === "repair_required"
|
||||
? "error"
|
||||
: String(item.data.status || "running");
|
||||
const taskId = String(item.data.taskId || "task");
|
||||
@@ -37,37 +33,25 @@ export function backendEventToUiChunk(
|
||||
? {
|
||||
eventId,
|
||||
sequence,
|
||||
...(review ? { review } : {}),
|
||||
}
|
||||
: {};
|
||||
return {
|
||||
type: "data-cad-progress",
|
||||
id: `event_${eventId}`,
|
||||
data: { step: item.event, label: ({
|
||||
image_observation: "参考图片观察", requirements_document_ready: "需求文档已冻结", completion_target_ready: "完成目标已冻结", requirements_compiled: "需求合同已编译", modeling_plan_ready: "建模计划已冻结", completion_result_ready: "完成结果已就绪", action_selection: "动作选择", tool_call: "建模工具", candidate_result: "候选构建", candidate_review: "候选独立复核", final_review: "最终独立复核", task_terminal: "生成任务",
|
||||
requirements_ready: "需求分析", authoring_cdsl_ready: "完整 CDSL", cdsl_compiled: "CDSL 编译", build_result: "CAD 构建", repair_started: "CDSL 修复", 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(";") : "")
|
||||
|| (review?.evidence instanceof Array ? review.evidence.join(";") : "")
|
||||
|| (review?.issues instanceof Array ? review.issues.map((issue) => typeof issue === "object" && issue ? String((issue as Record<string, unknown>).message || "") : String(issue)).filter(Boolean).join(";") : ""),
|
||||
|| (Array.isArray(item.data.questions) ? item.data.questions.map(String).filter(Boolean).join(";") : ""),
|
||||
),
|
||||
...(item.data.taskId ? { taskId } : {}),
|
||||
...(item.data.nodeId ? { nodeId: String(item.data.nodeId) } : {}),
|
||||
...(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) } : {}),
|
||||
...(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) } : {}),
|
||||
...(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) } : {}),
|
||||
...(item.data.invocationId ? { invocationId: String(item.data.invocationId) } : {}),
|
||||
...(item.data.arguments && typeof item.data.arguments === "object" ? { arguments: item.data.arguments as Record<string, unknown> } : {}),
|
||||
...(item.data.result !== undefined ? { result: item.data.result } : {}),
|
||||
...(Array.isArray(item.data.evidence) ? { evidence: item.data.evidence.map(String) } : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,25 +10,12 @@ export type CadProgress = {
|
||||
message?: string;
|
||||
markdown?: string;
|
||||
taskId?: string;
|
||||
nodeId?: string;
|
||||
tool?: string;
|
||||
invocationId?: string;
|
||||
arguments?: Record<string, unknown>;
|
||||
result?: unknown;
|
||||
evidence?: string[];
|
||||
questions?: string[];
|
||||
issues?: string[];
|
||||
blockerType?: string;
|
||||
userActionRequired?: boolean;
|
||||
verificationStatus?: "verified" | "completed_with_risks" | string;
|
||||
verificationWarnings?: string[];
|
||||
review?: Record<string, unknown>;
|
||||
clarificationPath?: string;
|
||||
lifecycle?: "running" | "completed" | "failed" | "waiting_retry" | "waiting_for_user" | string;
|
||||
attempt?: number;
|
||||
maxAttempts?: number;
|
||||
lifecycle?: "running" | "completed" | "failed" | "waiting_for_user" | string;
|
||||
path?: string;
|
||||
contractHash?: string;
|
||||
};
|
||||
|
||||
export type CadResult = {
|
||||
@@ -43,8 +30,6 @@ export type CadResult = {
|
||||
engine: string;
|
||||
checkpoint?: boolean;
|
||||
lifecycle?: "running" | "completed" | "failed" | string;
|
||||
verificationStatus?: "verified" | "completed_with_risks" | string;
|
||||
verificationWarnings?: string[];
|
||||
};
|
||||
|
||||
export type CadError = {
|
||||
@@ -97,12 +82,6 @@ export type TaskRevision = {
|
||||
engine?: string;
|
||||
error?: string;
|
||||
visibility?: "checkpoint" | "final" | "superseded" | string;
|
||||
parent_revision_id?: string;
|
||||
branch_id?: string;
|
||||
step_review_path?: string;
|
||||
candidate_review_path?: string;
|
||||
render_manifest_path?: string;
|
||||
visual_review_path?: string;
|
||||
};
|
||||
|
||||
export type TaskRecord = {
|
||||
@@ -111,71 +90,34 @@ export type TaskRecord = {
|
||||
current_revision: string;
|
||||
active_revision?: string;
|
||||
published_revision?: string;
|
||||
lifecycle?: "running" | "completed" | "failed" | "cancelled" | "waiting_retry" | "waiting_for_user" | string;
|
||||
lifecycle?: "running" | "completed" | "failed" | "cancelled" | "waiting_for_user" | string;
|
||||
phase?: string;
|
||||
state_version?: number;
|
||||
active_candidate_id?: string;
|
||||
requirements_spec?: Record<string, unknown> | null;
|
||||
requirements_spec_path?: string;
|
||||
repair_count?: number;
|
||||
repair_budget?: number;
|
||||
requirements_path?: string;
|
||||
authoring_path?: string;
|
||||
runtime_cdsl_path?: string;
|
||||
compile_audit_path?: string;
|
||||
diagnostics_path?: string;
|
||||
completion_path?: string;
|
||||
clarification_path?: string;
|
||||
requirements_contract?: Record<string, unknown> | null;
|
||||
requirements_contract_path?: string;
|
||||
requirements_markdown?: string | null;
|
||||
requirements_document_path?: string;
|
||||
completion_target_markdown?: string | null;
|
||||
completion_target_path?: string;
|
||||
feature_plan?: {
|
||||
requirements_analysis?: Record<string, unknown> | null;
|
||||
authoring_cdsl?: Record<string, unknown> | null;
|
||||
runtime_cdsl?: Record<string, unknown> | null;
|
||||
compile_audit?: Record<string, unknown> | null;
|
||||
diagnostics?: Record<string, unknown> | null;
|
||||
claim_report?: {
|
||||
schema_version?: string;
|
||||
parent_plan_hash?: string;
|
||||
replaces_node_ids?: string[];
|
||||
nodes?: Array<Record<string, unknown>>;
|
||||
final_claim_ids?: string[];
|
||||
claims?: Array<{ target?: string; status?: "pass" | "fail" | "pending" | "not_applicable" | string; verification?: 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<{
|
||||
requirement_id: string;
|
||||
claim_id: string;
|
||||
claim_kind: string;
|
||||
deterministic: boolean;
|
||||
status: "pass" | "pending" | "fail" | "unavailable" | string;
|
||||
evidence?: Record<string, unknown>;
|
||||
}>;
|
||||
checklist_progress?: Array<{
|
||||
requirement_id: string;
|
||||
statement: string;
|
||||
status: "pass" | "pending" | "fail" | string;
|
||||
}>;
|
||||
pending_action?: { action_id: string; working_head: string; intent: string; requirement_ids: string[]; atomic_id: string; expected_change: string; contract_hash: string } | null;
|
||||
action_ledger_summary?: Array<Record<string, unknown>>;
|
||||
usage?: { calls: number; prompt_tokens: number; completion_tokens: number; context_chars: number };
|
||||
usage?: { calls: number; records: Array<Record<string, unknown>> };
|
||||
preview_revision?: string;
|
||||
message?: string;
|
||||
questions?: string[];
|
||||
issues?: string[];
|
||||
blocker_type?: string;
|
||||
user_action_required?: boolean;
|
||||
verification_status?: "verified" | "completed_with_risks" | string;
|
||||
verification_warnings?: string[];
|
||||
revisions: TaskRevision[];
|
||||
};
|
||||
|
||||
@@ -191,6 +133,4 @@ export type BackendConfig = {
|
||||
configured: boolean;
|
||||
library_samples: number;
|
||||
autonomous_generation?: boolean;
|
||||
review_configured?: boolean;
|
||||
review_error?: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user