diff --git a/components/ai-cad/ai-cad-workbench.tsx b/components/ai-cad/ai-cad-workbench.tsx index e037b44b9..554720ddb 100644 --- a/components/ai-cad/ai-cad-workbench.tsx +++ b/components/ai-cad/ai-cad-workbench.tsx @@ -2325,6 +2325,7 @@ export function AiCadWorkbench() { const resultPanelRef = useRef(null); const localSavedAtRef = useRef>({}); const lastServerSavedSnapshotRef = useRef>({}); + const hasAutoCollapsedExplorerRef = useRef(false); const hasLocalEditsBeforeServerHydrationRef = useRef>( {} ); @@ -2430,6 +2431,28 @@ export function AiCadWorkbench() { writePersistedActiveWorkspaceId(activeWorkspaceId); }, [activeWorkspaceId]); + useEffect(() => { + if ( + hasAutoCollapsedExplorerRef.current || + panelDirection !== "horizontal" || + isLoadingWorkspaceList || + !hasHydratedFromStorage || + versions.length > 0 || + !historyPanelRef.current + ) { + return; + } + + hasAutoCollapsedExplorerRef.current = true; + historyPanelRef.current.collapse(); + setIsHistoryPanelCollapsed(true); + }, [ + hasHydratedFromStorage, + isLoadingWorkspaceList, + panelDirection, + versions.length, + ]); + useEffect(() => { if (!activeWorkspaceId) { setHasHydratedFromStorage(true); @@ -3562,29 +3585,6 @@ export function AiCadWorkbench() { -
- - - -
- - +
+ {versions.length} versions + {completedCount} done + + {hasPendingTasks + ? `${pendingTaskCount} task active` + : "Workspace stable"} +
@@ -3999,23 +3980,17 @@ export function AiCadWorkbench() { -
-
-
- - Session Context - - {activeVersion ? ( + {activeVersion ? ( +
+
+
+ + Session Context + Focus V{activeVersion.versionNumber} - ) : ( - - New thread - - )} -
- {activeVersion ? ( +
{getProviderLabel(activeVersion.provider)} @@ -4029,21 +4004,19 @@ export function AiCadWorkbench() { : "Initial"}
- ) : null} -
-

- {activeVersion - ? activeVersion.generationMode === "iterate" +

+

+ {activeVersion.generationMode === "iterate" ? `当前已经沿着 V${activeVersion.versionNumber} 进入连续修改模式。` - : `当前焦点在 V${activeVersion.versionNumber}。` - : "当前还是首轮对话阶段。"} -

-
+ : `当前焦点在 V${activeVersion.versionNumber}。`} +

+
+ ) : null} -
+
{messages.map((message) => { const linkedVersion = message.versionId ? findVersionById(versions, message.versionId) @@ -4273,77 +4246,83 @@ export function AiCadWorkbench() {
) : null} -
-
-
- Suggested Next Edits + {activeVersion ? ( +
+
+
+ Suggested Next Edits +
+ {semanticFocusInsights.length > 0 ? ( +
+ {semanticFocusInsights.map((insight) => ( + + {insight.shortLabel} + + ))} +
+ ) : null}
- {semanticFocusInsights.length > 0 ? ( -
- {semanticFocusInsights.map((insight) => ( - + {followUpSuggestions.slice(0, 3).map((item) => ( + + ))} +
+ +
+ Prompt Directives +
+
+ + {STRUCTURED_PROMPT_DIRECTIVES.map( + (directive) => ( + + ) + )} +
+ {promptStructuredDirectives.length > 0 ? ( +
+ {promptStructuredDirectives.map( + (directive) => ( + + {directive.label}: + {truncateText(directive.value, 22)} + + ) + )}
) : null}
-
- {followUpSuggestions.slice(0, 3).map((item) => ( - - ))} -
- -
- Prompt Directives -
-
- - {STRUCTURED_PROMPT_DIRECTIVES.map((directive) => ( - - ))} -
- {promptStructuredDirectives.length > 0 ? ( -
- {promptStructuredDirectives.map((directive) => ( - - {directive.label}: - {truncateText(directive.value, 22)} - - ))} -
- ) : null} -
+ ) : null}
@@ -4379,16 +4358,29 @@ export function AiCadWorkbench() {
- - {activeWorkspaceId - ? "1 workspace" - : "No workspace"} - {generationProvider === "kittycad-cad" - ? "KCL-ready" + ? "Fast" : modelVersion} + +
@@ -4553,6 +4545,30 @@ export function AiCadWorkbench() { 新建工作台 + +
) : null} @@ -5236,15 +5252,22 @@ export function AiCadWorkbench() { /> ) : ( - +
- 建模画布 + {activeVersion ? "建模画布" : "Canvas"} - 把中间区域收成更接近官方的大画布,预览优先,代码与对照放到下层。 + {activeVersion + ? "把中间区域收成更接近官方的大画布,预览优先,代码与对照放到下层。" + : "The center canvas stays focused on the current model."}
{activeVersion ? ( @@ -5256,969 +5279,1045 @@ export function AiCadWorkbench() { - -
-
-
-
- 视图环境 + {activeVersion ? ( + +
+
+
+
+ 视图环境 +
+
+ {viewerSettings.envPreset} +
-
- {viewerSettings.envPreset} +
+
+ 结果状态 +
+
+ {activeVersion + ? getStatusLabel(activeVersion.status) + : "等待生成"} +
+
+
+
+ 输出文件 +
+
+ {activeDownloadEntries.length > 0 + ? activeDownloadEntries + .slice(0, 3) + .map((item) => item.label) + .join(" / ") + : "暂无"} +
-
-
- 结果状态 -
-
- {activeVersion - ? getStatusLabel(activeVersion.status) - : "等待生成"} -
-
-
-
- 输出文件 -
-
- {activeDownloadEntries.length > 0 - ? activeDownloadEntries - .slice(0, 3) - .map((item) => item.label) - .join(" / ") - : "暂无"} -
-
-
- {previewSourceVersion ? ( -
- 当前版本先返回了代码结果,右侧 3D 预览暂时沿用 V - {previewSourceVersion.versionNumber} 作为参考。 -
- ) : null} + {previewSourceVersion ? ( +
+ 当前版本先返回了代码结果,右侧 3D 预览暂时沿用 + V{previewSourceVersion.versionNumber}{" "} + 作为参考。 +
+ ) : null} - {activeVersion && activeExecutionSummary ? ( -
- - - - - 执行摘要 - - - - {activeExecutionSummary} - - -
- ) : null} + {activeVersion && activeExecutionSummary ? ( +
+ + + + + 执行摘要 + + + + {activeExecutionSummary} + + +
+ ) : null} - - setActiveResultTab(value as "preview" | "code") - } - value={activeResultTab} - > - - + setActiveResultTab( + value as "preview" | "code" + ) + } + value={activeResultTab} + > + + + + 3D 预览 + + + + KCL 代码 + + + + - - 3D 预览 - - - - KCL 代码 - - - - -
- {compareCandidateVersions.length > 0 ? ( -
-
-
-
- - 双版本对照 +
+ {compareCandidateVersions.length > 0 ? ( +
+
+
+
+ + 双版本对照 +
+

+ 优先推荐父版本、同层变体和当前链路上的近邻版本,方便直接比对这轮修改有没有偏离。 +

-

- 优先推荐父版本、同层变体和当前链路上的近邻版本,方便直接比对这轮修改有没有偏离。 -

+ {compareVersion ? ( + + 当前对照 V + {compareVersion.versionNumber} + + ) : null}
- {compareVersion ? ( - - 当前对照 V - {compareVersion.versionNumber} - - ) : null} -
-
- {compareCandidateVersions - .slice(0, 8) - .map((version) => ( - - ))} -
-
- ) : null} - -
-
-
-
-
- {activeVersion - ? `当前版本 V${activeVersion.versionNumber}` - : "当前版本"} -
-

- 当前工作焦点 -

+
+ {compareCandidateVersions + .slice(0, 8) + .map((version) => ( + + ))}
- {activeVersion ? ( - - {getStatusLabel( - activeVersion.status - )} - - ) : null}
-
- -
-
+ ) : null} - {compareVersion ? ( +
- 对照版本 V - {compareVersion.versionNumber} + {activeVersion + ? `当前版本 V${activeVersion.versionNumber}` + : "当前版本"}

- {compareVersion.parentVersionId === - activeVersion?.id - ? "这是当前版本向后派生出的子变体。" - : compareVersion.id === - activeParentVersion?.id - ? "这是当前版本直接沿用的父版本。" - : "这是与当前版本最相关的对照节点。"} + 当前工作焦点

-
- + {activeVersion ? ( + {getStatusLabel( - compareVersion.status + activeVersion.status )} - -
+ ) : null}
- ) : null} -
- {versionDiffHighlights.length > 0 ? ( -
- {versionDiffHighlights.map( - (highlight) => ( -
- -

- {highlight} -

-
- ) - )} -
- ) : null} -
- - - -
- {compareVersion ? ( -
-
-
- - KCL 双版本对照 -
- -
-

- 这里会并排显示当前版本和对照版本的代码结果,方便检查这轮连续迭代到底改动了哪些约束和结构表达。 -

-
- ) : null} - - {compareVersion ? ( -
- - 新增 {codeDiffResult.summary.added} - - - 删除 {codeDiffResult.summary.removed} - - - 修改 {codeDiffResult.summary.changed} - - - 未变 {codeDiffResult.summary.unchanged} - -
- ) : null} - - {compareVersion && - semanticCodeDiffInsights.length > 0 ? ( -
-
-
- - 设计语义摘要 -
-
- {semanticCodeDiffInsights.map( - (insight) => ( + {compareVersion ? ( +
+
+
+
+ 对照版本 V + {compareVersion.versionNumber} +
+

+ {compareVersion.parentVersionId === + activeVersion?.id + ? "这是当前版本向后派生出的子变体。" + : compareVersion.id === + activeParentVersion?.id + ? "这是当前版本直接沿用的父版本。" + : "这是与当前版本最相关的对照节点。"} +

+
+
- {insight.shortLabel}{" "} - {insight.count} - - ) - )} -
-
-

- 这层摘要会优先把 KCL - 里的差异翻译成更接近设计语言的改动方向,方便先判断本轮是不是在改你关心的结构。 -

-
- {semanticCodeDiffInsights.map( - (insight) => ( -
-
-
-
- {insight.label} -
-

- {insight.detail} -

-
- - 命中 {insight.count} - -
- {insight.examples.length > 0 ? ( -
- {insight.examples.map( - (example) => ( -
- {example} -
- ) - )} -
- ) : null} -
- ) - )} -
-
- ) : null} - - {compareVersion && - codeDiffInsights.length > 0 ? ( -
- {codeDiffInsights.map((insight) => ( -
- -

- {insight} -

-
- ))} -
- ) : null} - - {codeActionError ? ( -
- {codeActionError} -
- ) : null} - -
- {compareVersion ? ( - - swallowAsync( - handleCopyCodeContent(code) - ) - } - openUrl={activeCodeUrl} - rows={visibleCodeDiffRows} - rowsEmptyMessage="当前筛选下,当前版本没有需要展示的差异行。" - side="right" - subtitle={ - activeCodeLineCount > 0 - ? `当前共 ${activeCodeLineCount} 行。` - : "连续迭代返回的代码会优先显示在这里。" - } - title={ - activeVersion - ? `当前版本 V${activeVersion.versionNumber} KCL` - : "KCL 代码" - } - /> - ) : ( -
-
-
-
- {activeVersion - ? `当前版本 V${activeVersion.versionNumber} KCL` - : "KCL 代码"} -
-

- {activeCodeLineCount > 0 - ? `当前共 ${activeCodeLineCount} 行。` - : "连续迭代返回的代码会优先显示在这里。"} -

-
-
- {activeCodeUrl ? ( - - ) : null} -
-
- - -
- {isLoadingActiveCodePreview ? ( -
-
- - 正在加载当前版本 KCL... -
-
- ) : activeCodePreviewError ? ( -
- 当前版本 KCL 暂时无法预览: - {activeCodePreviewError} -
- ) : activeCodeContent ? ( - - - setCodeActionError(null) - } - onError={(error) => { - setCodeActionError( - error instanceof Error - ? error.message - : "复制 KCL 代码失败" - ); - }} - size="icon" - variant="ghost" - /> - - ) : ( -
- 当前版本还没有可预览的 KCL - 代码。 -
- )} -
-
-
- )} - - {compareVersion ? ( - - swallowAsync( - handleCopyCodeContent(code) - ) - } - openUrl={compareCodeUrl} - rows={visibleCodeDiffRows} - rowsEmptyMessage="当前筛选下,对照版本没有需要展示的差异行。" - side="left" - subtitle={ - compareCodeLineCount > 0 - ? `当前共 ${compareCodeLineCount} 行。` - : "如果这版只生成了 3D 或还没返回代码,这里会保持空白。" - } - title={`对照版本 V${compareVersion.versionNumber} KCL`} - /> - ) : null} -
-
- - - -
-
-
-
-
- {activeVersion - ? `V${activeVersion.versionNumber} 设计摘要` - : "当前没有激活版本"} -
-

- {activeVersion - ? activeVersion.prompt - : "在左侧输入你的 CAD 需求,工作台会开始生成第一版。"} -

- {activeVersion ? ( -
-

- 当前版本由{" "} - {getProviderLabel( - activeVersion.provider - )}{" "} - 生成, - {activeVersion.modelVersion} -

- {activeParentVersion ? ( -

- 本轮基于 V - {activeParentVersion.versionNumber}{" "} - 连续修改。 -

- ) : null} - {previewSourceVersion ? ( -

- 当前显示的 3D 预览来自 V - {previewSourceVersion.versionNumber} - 。 -

- ) : null} -
- ) : null} -
- {primaryDownloadEntry ? ( - - ) : ( - - )} -
- - {activeVersion?.errorMessage ? ( - <> - -

- {activeVersion.errorMessage} -

- - ) : null} - - {activeDownloadEntries.length > 1 ? ( - <> - -
- {activeDownloadEntries - .slice(0, 6) - .map((entry) => ( - - ))} -
- - ) : null} - - {activeVersion ? ( - <> - -
-
- - 版本对比 -
- - {activeVersionLineage.length > 0 ? ( -
- {activeVersionLineage.map( - (lineageVersion) => ( - - ) - )} +
+
+
+ +
) : null} +
-
-
-
- - {compareVersion - ? `对照版本 V${compareVersion.versionNumber}` - : "起始版本"} -
-

- {compareVersion - ? truncateText( - compareVersion.prompt, - 84 - ) - : "当前版本是这条设计链的起点,还没有可供对照的其他版本。"} -

- {compareVersion ? ( - <> -
- - {getProviderLabel( - compareVersion.provider - )} - - - {getStatusLabel( - compareVersion.status - )} - -
- {compareStructuredDirectives.length > - 0 ? ( -
- {compareStructuredDirectives - .slice(0, 3) - .map((directive) => ( - - {directive.label} - - ))} -
- ) : null} - - ) : null} -
- -
-
- - 当前版本 V - {activeVersion.versionNumber} -
-

- {truncateText( - activeVersion.prompt, - 84 - )} -

-
- - {getProviderLabel( - activeVersion.provider - )} - - - {getStatusLabel( - activeVersion.status - )} - - {activeVersion.generationMode === - "iterate" ? ( - - 连续修改 - - ) : null} -
- {activeVersionStructuredDirectives.length > - 0 ? ( -
- {activeVersionStructuredDirectives.map( - (directive) => ( - - {directive.label} - - ) - )} -
- ) : null} -
-
- - {versionCompareNotes.length > 0 ? ( -
- {versionCompareNotes.map((note) => ( + {versionDiffHighlights.length > 0 ? ( +
+ {versionDiffHighlights.map( + (highlight) => (

- {note} + {highlight}

- ))} + ) + )} +
+ ) : null} +
+ + + +
+ {compareVersion ? ( +
+
+
+ + KCL 双版本对照 +
+ +
+

+ 这里会并排显示当前版本和对照版本的代码结果,方便检查这轮连续迭代到底改动了哪些约束和结构表达。 +

+
+ ) : null} + + {compareVersion ? ( +
+ + 新增 {codeDiffResult.summary.added} + + + 删除 {codeDiffResult.summary.removed} + + + 修改 {codeDiffResult.summary.changed} + + + 未变{" "} + {codeDiffResult.summary.unchanged} + +
+ ) : null} + + {compareVersion && + semanticCodeDiffInsights.length > 0 ? ( +
+
+
+ + 设计语义摘要 +
+
+ {semanticCodeDiffInsights.map( + (insight) => ( + + {insight.shortLabel}{" "} + {insight.count} + + ) + )} +
+
+

+ 这层摘要会优先把 KCL + 里的差异翻译成更接近设计语言的改动方向,方便先判断本轮是不是在改你关心的结构。 +

+
+ {semanticCodeDiffInsights.map( + (insight) => ( +
+
+
+
+ {insight.label} +
+

+ {insight.detail} +

+
+ + 命中 {insight.count} + +
+ {insight.examples.length > 0 ? ( +
+ {insight.examples.map( + (example) => ( +
+ {example} +
+ ) + )} +
+ ) : null} +
+ ) + )} +
+
+ ) : null} + + {compareVersion && + codeDiffInsights.length > 0 ? ( +
+ {codeDiffInsights.map((insight) => ( +
+ +

+ {insight} +

+
+ ))} +
+ ) : null} + + {codeActionError ? ( +
+ {codeActionError} +
+ ) : null} + +
+ {compareVersion ? ( + + swallowAsync( + handleCopyCodeContent(code) + ) + } + openUrl={activeCodeUrl} + rows={visibleCodeDiffRows} + rowsEmptyMessage="当前筛选下,当前版本没有需要展示的差异行。" + side="right" + subtitle={ + activeCodeLineCount > 0 + ? `当前共 ${activeCodeLineCount} 行。` + : "连续迭代返回的代码会优先显示在这里。" + } + title={ + activeVersion + ? `当前版本 V${activeVersion.versionNumber} KCL` + : "KCL 代码" + } + /> + ) : ( +
+
+
+
+ {activeVersion + ? `当前版本 V${activeVersion.versionNumber} KCL` + : "KCL 代码"} +
+

+ {activeCodeLineCount > 0 + ? `当前共 ${activeCodeLineCount} 行。` + : "连续迭代返回的代码会优先显示在这里。"} +

+
+
+ {activeCodeUrl ? ( + + ) : null} +
+
+ + +
+ {isLoadingActiveCodePreview ? ( +
+
+ + 正在加载当前版本 KCL... +
+
+ ) : activeCodePreviewError ? ( +
+ 当前版本 KCL 暂时无法预览: + {activeCodePreviewError} +
+ ) : activeCodeContent ? ( + + + setCodeActionError(null) + } + onError={(error) => { + setCodeActionError( + error instanceof Error + ? error.message + : "复制 KCL 代码失败" + ); + }} + size="icon" + variant="ghost" + /> + + ) : ( +
+ 当前版本还没有可预览的 KCL + 代码。 +
+ )} +
+
+
+ )} + + {compareVersion ? ( + + swallowAsync( + handleCopyCodeContent(code) + ) + } + openUrl={compareCodeUrl} + rows={visibleCodeDiffRows} + rowsEmptyMessage="当前筛选下,对照版本没有需要展示的差异行。" + side="left" + subtitle={ + compareCodeLineCount > 0 + ? `当前共 ${compareCodeLineCount} 行。` + : "如果这版只生成了 3D 或还没返回代码,这里会保持空白。" + } + title={`对照版本 V${compareVersion.versionNumber} KCL`} + /> + ) : null} +
+
+
+ + +
+
+
+
+
+ {activeVersion + ? `V${activeVersion.versionNumber} 设计摘要` + : "当前没有激活版本"} +
+

+ {activeVersion + ? activeVersion.prompt + : "在左侧输入你的 CAD 需求,工作台会开始生成第一版。"} +

+ {activeVersion ? ( +
+

+ 当前版本由{" "} + {getProviderLabel( + activeVersion.provider + )}{" "} + 生成, + {activeVersion.modelVersion} +

+ {activeParentVersion ? ( +

+ 本轮基于 V + { + activeParentVersion.versionNumber + }{" "} + 连续修改。 +

+ ) : null} + {previewSourceVersion ? ( +

+ 当前显示的 3D 预览来自 V + { + previewSourceVersion.versionNumber + } + 。 +

+ ) : null}
) : null}
- - ) : null} -
- -
-
- - 查看器设置 -
-
-
-
- 环境贴图 -
- -
- -
-
-
- 自动旋转 -
-
- 更像产品展示台 -
-
- - setViewerSettings((current) => ({ - ...current, - autoRotate: checked, - })) - } - /> -
- -
-
-
- 网格地面 -
-
- 方便观察尺度 -
-
- - setViewerSettings((current) => ({ - ...current, - showGrid: checked, - })) - } - /> -
- -
-
-
- 线框模式 -
-
- 快速看结构面 -
-
- - setViewerSettings((current) => ({ - ...current, - wireframe: checked, - })) - } - /> -
- - {primaryDownloadEntry ? ( - + + + 下载 {primaryDownloadEntry.label} + + + ) : ( + + )} +
+ + {activeVersion?.errorMessage ? ( + <> + +

+ {activeVersion.errorMessage} +

+ ) : null} + + {activeDownloadEntries.length > 1 ? ( + <> + +
+ {activeDownloadEntries + .slice(0, 6) + .map((entry) => ( + + ))} +
+ + ) : null} + + {activeVersion ? ( + <> + +
+
+ + 版本对比 +
+ + {activeVersionLineage.length > 0 ? ( +
+ {activeVersionLineage.map( + (lineageVersion) => ( + + ) + )} +
+ ) : null} + +
+
+
+ + {compareVersion + ? `对照版本 V${compareVersion.versionNumber}` + : "起始版本"} +
+

+ {compareVersion + ? truncateText( + compareVersion.prompt, + 84 + ) + : "当前版本是这条设计链的起点,还没有可供对照的其他版本。"} +

+ {compareVersion ? ( + <> +
+ + {getProviderLabel( + compareVersion.provider + )} + + + {getStatusLabel( + compareVersion.status + )} + +
+ {compareStructuredDirectives.length > + 0 ? ( +
+ {compareStructuredDirectives + .slice(0, 3) + .map((directive) => ( + + {directive.label} + + ))} +
+ ) : null} + + ) : null} +
+ +
+
+ + 当前版本 V + {activeVersion.versionNumber} +
+

+ {truncateText( + activeVersion.prompt, + 84 + )} +

+
+ + {getProviderLabel( + activeVersion.provider + )} + + + {getStatusLabel( + activeVersion.status + )} + + {activeVersion.generationMode === + "iterate" ? ( + + 连续修改 + + ) : null} +
+ {activeVersionStructuredDirectives.length > + 0 ? ( +
+ {activeVersionStructuredDirectives.map( + (directive) => ( + + {directive.label} + + ) + )} +
+ ) : null} +
+
+ + {versionCompareNotes.length > 0 ? ( +
+ {versionCompareNotes.map((note) => ( +
+ +

+ {note} +

+
+ ))} +
+ ) : null} +
+ + ) : null} +
+ +
+
+ + 查看器设置 +
+
+
+
+ 环境贴图 +
+ +
+ +
+
+
+ 自动旋转 +
+
+ 更像产品展示台 +
+
+ + setViewerSettings((current) => ({ + ...current, + autoRotate: checked, + })) + } + /> +
+ +
+
+
+ 网格地面 +
+
+ 方便观察尺度 +
+
+ + setViewerSettings((current) => ({ + ...current, + showGrid: checked, + })) + } + /> +
+ +
+
+
+ 线框模式 +
+
+ 快速看结构面 +
+
+ + setViewerSettings((current) => ({ + ...current, + wireframe: checked, + })) + } + /> +
+ + {primaryDownloadEntry ? ( + + ) : null} +
+
+
+
+ + ) : ( +
+
+
+ Design Canvas + Ready for first pass +
+
+ + +
+
+ +
+
+
+
+
+
+
+
+
Top
+
Front
+
Right
+
+
+
+
+
+
+ Start a design to create geometry +
+

+ 从右侧直接描述零件、尺寸和约束,画布会在这里保持当前模型。 +

- + )} )}