From 2746152a213998a488d0eb8f56ab40b2045ecafe Mon Sep 17 00:00:00 2001 From: coso Date: Fri, 24 Apr 2026 11:12:20 +0800 Subject: [PATCH] fix(release): finalize v1.18.0 --- .github/workflows/release.yml | 4 +- RELEASE_NOTES.md | 9 +++- docs/exec-plans/limenext-progress.md | 20 +++++++++ .../agent/chat/components/EmptyState.test.tsx | 7 ++-- .../agent/chat/components/EmptyState.tsx | 41 +++++++++++-------- .../agent/chat/components/ImageTaskViewer.tsx | 27 ++++++++++++ .../skill-selection/CharacterMention.test.tsx | 2 - .../skill-selection/CharacterMentionPanel.tsx | 8 ++-- .../inputCapabilitySections.ts | 5 +-- .../api-key/ProviderModelList.tsx | 1 - 10 files changed, 89 insertions(+), 35 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76a1ae604..1bb3270e2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -594,12 +594,12 @@ jobs: find "$bundle_dir" -maxdepth 4 -type f | sort done - - name: Fail when macOS notarized build is unavailable + - name: Fail when macOS release build is unavailable if: startsWith(matrix.platform, 'macos') && steps.build_macos_primary.outcome == 'failure' && steps.build_macos_retry.outcome == 'failure' shell: bash run: | set -euo pipefail - echo "::error::macOS notarization failed twice. Blocking release instead of publishing a signed-only artifact." + echo "::error::macOS release build failed twice before a notarized artifact became available. See the previous build attempt logs for the actual error." exit 1 - name: Resolve macOS bundle dir diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 21fd8177d..cdc1341c4 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,7 +6,7 @@ - 本次发布目标 tag 为 `v1.18.0`。 - 本说明按当前待递交工作树重新整理,覆盖这次准备一起递交的版本同步、Rust/runtime、前端工作台、SceneApp、Memory、automation、bridge、roadmap 文档与 Playwright 复盘材料,不再沿用旧版“只写版本号”的简化摘要。 -- 截至本次整理,待递交范围包含 `154` 个已跟踪文件改动、`27` 个未跟踪新增项,总计 `16506` 行新增、`1787` 行删除。 +- 本次重新发布还补充纳入了聊天空态、技能入口、图片预览容错,以及 macOS release workflow 诊断文案修正,确保 `v1.18.0` 对外指向的是当前完整提交状态。 ### 递交范围 @@ -23,6 +23,13 @@ ### 重点更新 +#### 0. 补充收口:发布前端构建阻断与 release 诊断信息校正 + +- `src/components/agent/chat/components/{EmptyState,ImageTaskViewer}.tsx`、`src/components/agent/chat/skill-selection/{CharacterMentionPanel,inputCapabilitySections}.ts` 与配套测试继续收口聊天空态、技能入口和图片预览体验。 +- `src/components/provider-pool/api-key/ProviderModelList.tsx` 修正 provider 模型来源判断的类型收窄问题,避免 release 构建因前端 TypeScript 报错提前中断。 +- `ImageTaskViewer.tsx` 为补图预览和弹窗预览统一补齐 `RenderableTaskImage` 的 fallback 渲染,避免新 props 约束下的构建失败。 +- `.github/workflows/release.yml` 将原先误导性的 “macOS notarization failed twice” 兜底报错改成“release build failed before notarized artifact became available”,方便后续直接定位真实前序构建错误,而不是被公证文案误导。 + #### 1. Agent runtime、任务层与模型层主线继续 current 化 - `src-tauri/crates/agent/src/session_execution_runtime.rs`、`protocol.rs`、`provider_safety.rs`、`credential_bridge.rs`,以及 `src-tauri/src/commands/aster_agent_cmd/{request_model_resolution,runtime_turn,dto,subagent_runtime}.rs` 继续扩展 runtime 路由、任务画像、provider 安全边界、会话上下文与事件投影。 diff --git a/docs/exec-plans/limenext-progress.md b/docs/exec-plans/limenext-progress.md index 1cfa58e64..0f583e23c 100644 --- a/docs/exec-plans/limenext-progress.md +++ b/docs/exec-plans/limenext-progress.md @@ -5842,3 +5842,23 @@ - `vitest` 通过:`3 files / 43 tests passed` - `eslint` 通过 - `verify:gui-smoke` 通过:`workspace-ready / browser-runtime / site-adapters / agent-service-skill-entry / agent-runtime-tool-surface / agent-runtime-tool-surface-page` +- 首页 `EmptyState` 与 slash 首屏当前又继续前推了一刀,避免 `我的方法` 页已经收成前台起手层,但首页推荐 shelf 和 `/` 首屏里还残留 `围绕最近成果 / 围绕最近复盘 / 结果模板 / 我的方法` 这类 badge-first 呈现: + - `EmptyState` 当前已把结果卡和续接卡的 badge 降为可选辅助字段;默认不再把 `结果模板 / 我的方法 / 围绕最近...` 顶在卡头 + - 首页推荐卡当前继续保留“为什么推荐这条”,但这层信息已退回正文 `meta / contextSummary`,不再用 badge 抢标题层 + - slash `先拿结果` 当前已把 curated task 行项目右侧 `kindLabel` 收掉;分组标题负责解释“这是结果模板”,行内只保留标题和合同描述 + - slash 里的最近复盘横幅当前也已去掉 badge pill,只保留 `最近复盘已更新`、摘要和 `继续去...` 动作 +- 因此用户当前沿着 `首页 -> 结果入口` 和 `slash -> 先拿结果` 两条主链时,看到的更接近“为什么现在该从这条开始”,而不是“这是哪个标签下的哪个对象”: + - 首页结果入口当前会先展示动作对象与推荐原因 + - slash 首屏当前会先展示结果模板本身与启动合同,不再把标签塞到标题右侧 + - 最近复盘 / 当前参考 / 最近成果这些高价值信号当前仍保留,但统一退到了正文说明层 +- 这一步继续遵守 P1 / P2 的 current 边界: + - 不新增首页专属推荐状态机 + - 不新增 slash 首屏第二套结果模板协议 + - 不改结果模板排序、launcher、`onSelectCuratedTask` 与现有 route 主链,只做前台呈现减法 +- 这次子改动的定向验证当前已通过: + - `npm exec vitest run "src/components/agent/chat/components/EmptyState.test.tsx" "src/components/agent/chat/skill-selection/CharacterMention.test.tsx" "src/components/agent/chat/skill-selection/inputCapabilitySections.test.ts"` + - `npx eslint "src/components/agent/chat/components/EmptyState.tsx" "src/components/agent/chat/components/EmptyState.test.tsx" "src/components/agent/chat/skill-selection/inputCapabilitySections.ts" "src/components/agent/chat/skill-selection/inputCapabilitySections.test.ts" "src/components/agent/chat/skill-selection/CharacterMentionPanel.tsx" "src/components/agent/chat/skill-selection/CharacterMention.test.tsx"` + - `npm run verify:gui-smoke -- --timeout-ms 180000` + - `vitest` 通过:`3 files / 140 tests passed` + - `eslint` 通过 + - `verify:gui-smoke` 通过:`workspace-ready / browser-runtime / site-adapters / agent-service-skill-entry / agent-runtime-tool-surface / agent-runtime-tool-surface-page` diff --git a/src/components/agent/chat/components/EmptyState.test.tsx b/src/components/agent/chat/components/EmptyState.test.tsx index c24b742c6..43f58bdff 100644 --- a/src/components/agent/chat/components/EmptyState.test.tsx +++ b/src/components/agent/chat/components/EmptyState.test.tsx @@ -592,10 +592,9 @@ describe("EmptyState", () => { ); expect(reviewCard?.textContent).toContain("复盘这个账号/项目"); - expect(reviewCard?.textContent).toContain("围绕最近复盘"); expect(reviewCard?.textContent).toContain("复盘:短视频编排"); expect(breakdownCard?.textContent).toContain("拆解一条爆款内容"); - expect(breakdownCard?.textContent).toContain("围绕最近复盘"); + expect(breakdownCard?.textContent).toContain("复盘:短视频编排"); expect(reviewBanner?.textContent).toContain("最近复盘已更新"); expect(reviewBanner?.textContent).toContain("短视频编排 · 补证据"); expect(reviewBanner?.textContent).toContain("这轮结果还缺证据"); @@ -2156,7 +2155,7 @@ describe("EmptyState", () => { await Promise.resolve(); }); - expect(container.textContent).toContain("围绕当前参考"); + expect(container.textContent).toContain("参考:品牌风格样本"); expect(container.textContent).toContain("内容主稿生成"); }); @@ -2221,7 +2220,7 @@ describe("EmptyState", () => { await Promise.resolve(); }); - expect(container.textContent).toContain("围绕最近成果"); + expect(container.textContent).toContain("成果:账号复盘结论"); expect(container.textContent).toContain("复盘这个账号/项目"); }); diff --git a/src/components/agent/chat/components/EmptyState.tsx b/src/components/agent/chat/components/EmptyState.tsx index 54726f72c..449dda9dd 100644 --- a/src/components/agent/chat/components/EmptyState.tsx +++ b/src/components/agent/chat/components/EmptyState.tsx @@ -559,7 +559,7 @@ type RecommendationShelfItem = key: string; title: string; summary: string; - badge: string; + badge?: string; hint: string; meta: string; contextSummary?: string; @@ -573,7 +573,7 @@ type RecommendationShelfItem = key: string; title: string; summary: string; - badge: string; + badge?: string; hint: string; meta: string; contextSummary?: string; @@ -587,7 +587,7 @@ interface ContinuationShelfItem { key: string; title: string; summary: string; - badge: string; + badge?: string; usedAt: number; testId: string; onSelect: () => void; @@ -1309,7 +1309,6 @@ export const EmptyState: React.FC = ({ key: template.id, title: template.title, summary: template.summary, - badge: featured.badgeLabel, hint: template.outputHint, meta: `${metaPrefix}${buildCuratedTaskCapabilityDescription(template, { includeSummary: false, @@ -1489,7 +1488,6 @@ export const EmptyState: React.FC = ({ ] .filter((segment) => segment.length > 0) .join(" · "), - badge: "结果模板", usedAt: template.recentUsedAt as number, testId: `entry-continuation-solution-${template.id}`, onSelect: () => @@ -1525,7 +1523,6 @@ export const EmptyState: React.FC = ({ ] .filter((segment) => segment.length > 0) .join(" · "), - badge: "我的方法", usedAt, testId: `entry-continuation-method-${skill.key}`, onSelect: () => { @@ -1572,7 +1569,6 @@ export const EmptyState: React.FC = ({ ] .filter((segment) => segment.length > 0) .join(" · "), - badge: "我的方法", usedAt, testId: `entry-continuation-method-${skill.id}`, onSelect: () => { @@ -1815,7 +1811,6 @@ export const EmptyState: React.FC = ({ {reviewFeedbackBanner ? ( - 围绕最近复盘 最近复盘已更新:{reviewFeedbackBanner.title} @@ -1847,7 +1842,9 @@ export const EmptyState: React.FC = ({ segment.trim().length > 0) + .join(" · ")} onClick={() => { leadRecommendationItem.onSelect(); }} @@ -1856,9 +1853,11 @@ export const EmptyState: React.FC = ({ {resolveLeadRecommendationEyebrow(creationReplaySurface)} - - {leadRecommendationItem.badge} - + {leadRecommendationItem.badge ? ( + + {leadRecommendationItem.badge} + + ) : null} {leadRecommendationItem.title} @@ -1897,7 +1896,9 @@ export const EmptyState: React.FC = ({ key={item.key} type="button" data-testid={item.testId} - title={`${item.badge} · ${item.summary} · ${item.meta}`} + title={[item.summary, item.meta] + .filter((segment) => segment.trim().length > 0) + .join(" · ")} onClick={() => { item.onSelect(); }} @@ -1906,9 +1907,11 @@ export const EmptyState: React.FC = ({ {item.title} - - {item.badge} - + {item.badge ? ( + + {item.badge} + + ) : null} {item.contextSummary @@ -1934,7 +1937,7 @@ export const EmptyState: React.FC = ({ key={item.key} type="button" data-testid={item.testId} - title={`${item.badge} · ${item.summary}`} + title={item.summary} onClick={() => { item.onSelect(); }} @@ -1943,7 +1946,9 @@ export const EmptyState: React.FC = ({ {item.title} - {item.badge} + {item.badge ? ( + {item.badge} + ) : null} {item.summary} diff --git a/src/components/agent/chat/components/ImageTaskViewer.tsx b/src/components/agent/chat/components/ImageTaskViewer.tsx index 9f9676289..b9f611252 100644 --- a/src/components/agent/chat/components/ImageTaskViewer.tsx +++ b/src/components/agent/chat/components/ImageTaskViewer.tsx @@ -846,6 +846,21 @@ export function ImageTaskViewer({ src={selectedOutput.url} alt={selectedOutput.prompt || "图片任务结果"} className="h-full w-full object-contain" + renderFallback={(reason) => ( +
+
+ +
+ {reason === "error" ? "预览加载失败" : "暂无可预览图片"} +
+
+ {reason === "error" + ? "这张图片暂时无法在预览窗口中展示,请稍后重试或在新窗口打开。" + : "当前没有可展示的图片结果。"} +
+
+
+ )} /> ) : null} {selectedTaskOutputs.length > 1 ? ( @@ -926,6 +941,18 @@ export function ImageTaskViewer({ "w-full object-cover", resolveOutputTileAspectClass(selectedTask?.layoutHint), )} + renderFallback={() => ( +
+ 预览失败 +
+ )} /> {resolveOutputDisplayIndex(index, output.slotIndex)} diff --git a/src/components/agent/chat/skill-selection/CharacterMention.test.tsx b/src/components/agent/chat/skill-selection/CharacterMention.test.tsx index 8a62ddaf1..669cd36f7 100644 --- a/src/components/agent/chat/skill-selection/CharacterMention.test.tsx +++ b/src/components/agent/chat/skill-selection/CharacterMention.test.tsx @@ -2707,7 +2707,6 @@ describe("CharacterMention", () => { await typeSlashAndWait(textarea); - expect(document.body.textContent).toContain("围绕最近成果"); expect(document.body.textContent).toContain("成果:本周账号复盘线索"); const resultTemplateSection = Array.from( @@ -2757,7 +2756,6 @@ describe("CharacterMention", () => { const banner = document.body.querySelector( '[data-testid="input-capability-section-banner-result-templates"]', ); - expect(banner?.textContent).toContain("围绕最近复盘"); expect(banner?.textContent).toContain("最近复盘已更新:短视频编排 · 补证据"); expect(banner?.textContent).toContain("这轮结果还缺证据"); expect(banner?.textContent).toContain("这轮复盘更建议优先回到"); diff --git a/src/components/agent/chat/skill-selection/CharacterMentionPanel.tsx b/src/components/agent/chat/skill-selection/CharacterMentionPanel.tsx index 12468c973..0eb6ac551 100644 --- a/src/components/agent/chat/skill-selection/CharacterMentionPanel.tsx +++ b/src/components/agent/chat/skill-selection/CharacterMentionPanel.tsx @@ -333,9 +333,11 @@ export const CharacterMentionPanel: React.FC = ({
- - {section.banner.badge} - + {section.banner.badge ? ( + + {section.banner.badge} + + ) : null}
{section.banner.title}
diff --git a/src/components/agent/chat/skill-selection/inputCapabilitySections.ts b/src/components/agent/chat/skill-selection/inputCapabilitySections.ts index 5b3c44376..a87d4adbc 100644 --- a/src/components/agent/chat/skill-selection/inputCapabilitySections.ts +++ b/src/components/agent/chat/skill-selection/inputCapabilitySections.ts @@ -110,7 +110,7 @@ export interface InputCapabilitySection { heading: string; items: InputCapabilityDescriptor[]; banner?: { - badge: string; + badge?: string; title: string; summary: string; footnote?: string; @@ -1276,8 +1276,6 @@ function buildSlashCapabilitySections( }), icon: "sparkles" as const, iconClassName: "mr-2 h-4 w-4 text-amber-600", - kindLabel: - featuredCuratedTaskTemplateMap.get(task.id)?.badgeLabel ?? task.badge, task, launchInputValues: launchContext.launchPrefill?.inputValues, referenceMemoryIds: launchContext.mergedReferenceMemoryIds, @@ -1311,7 +1309,6 @@ function buildSlashCapabilitySections( null; return { - badge: "围绕最近复盘", title: `最近复盘已更新:${latestReviewSignal.title}`, summary: truncateSectionBannerText( [ diff --git a/src/components/provider-pool/api-key/ProviderModelList.tsx b/src/components/provider-pool/api-key/ProviderModelList.tsx index c1bc64e95..0b2b4184e 100644 --- a/src/components/provider-pool/api-key/ProviderModelList.tsx +++ b/src/components/provider-pool/api-key/ProviderModelList.tsx @@ -593,7 +593,6 @@ export const ProviderModelList: React.FC = ({ preservesCurrentProviderCustomModels || (!autoFetchCapability.requiresLiveModelTruth && (normalizedSource === "Catalog" || - normalizedSource === "CustomModels" || normalizedSource === "LocalFallback")); if (result && result.models) {