mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
fix(release): finalize v1.18.0
This commit is contained in:
@@ -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
|
||||
|
||||
+8
-1
@@ -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 安全边界、会话上下文与事件投影。
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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("复盘这个账号/项目");
|
||||
});
|
||||
|
||||
|
||||
@@ -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<EmptyStateProps> = ({
|
||||
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<EmptyStateProps> = ({
|
||||
]
|
||||
.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<EmptyStateProps> = ({
|
||||
]
|
||||
.filter((segment) => segment.length > 0)
|
||||
.join(" · "),
|
||||
badge: "我的方法",
|
||||
usedAt,
|
||||
testId: `entry-continuation-method-${skill.key}`,
|
||||
onSelect: () => {
|
||||
@@ -1572,7 +1569,6 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
|
||||
]
|
||||
.filter((segment) => segment.length > 0)
|
||||
.join(" · "),
|
||||
badge: "我的方法",
|
||||
usedAt,
|
||||
testId: `entry-continuation-method-${skill.id}`,
|
||||
onSelect: () => {
|
||||
@@ -1815,7 +1811,6 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
|
||||
{reviewFeedbackBanner ? (
|
||||
<RecommendationSignalBanner data-testid="entry-review-feedback-banner">
|
||||
<RecommendationSignalBannerHeader>
|
||||
<RecommendationShelfBadge>围绕最近复盘</RecommendationShelfBadge>
|
||||
<RecommendationSignalBannerTitle>
|
||||
最近复盘已更新:{reviewFeedbackBanner.title}
|
||||
</RecommendationSignalBannerTitle>
|
||||
@@ -1847,7 +1842,9 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
|
||||
<RecommendationLeadCard
|
||||
type="button"
|
||||
data-testid={leadRecommendationItem.testId}
|
||||
title={`${leadRecommendationItem.badge} · ${leadRecommendationItem.summary} · ${leadRecommendationItem.meta}`}
|
||||
title={[leadRecommendationItem.summary, leadRecommendationItem.meta]
|
||||
.filter((segment) => segment.trim().length > 0)
|
||||
.join(" · ")}
|
||||
onClick={() => {
|
||||
leadRecommendationItem.onSelect();
|
||||
}}
|
||||
@@ -1856,9 +1853,11 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
|
||||
<RecommendationLeadEyebrow>
|
||||
{resolveLeadRecommendationEyebrow(creationReplaySurface)}
|
||||
</RecommendationLeadEyebrow>
|
||||
<RecommendationShelfInlineBadge>
|
||||
{leadRecommendationItem.badge}
|
||||
</RecommendationShelfInlineBadge>
|
||||
{leadRecommendationItem.badge ? (
|
||||
<RecommendationShelfInlineBadge>
|
||||
{leadRecommendationItem.badge}
|
||||
</RecommendationShelfInlineBadge>
|
||||
) : null}
|
||||
</RecommendationLeadEyebrowRow>
|
||||
<RecommendationLeadTitle>
|
||||
{leadRecommendationItem.title}
|
||||
@@ -1897,7 +1896,9 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
|
||||
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<EmptyStateProps> = ({
|
||||
<RecommendationAssistCardTitle>
|
||||
{item.title}
|
||||
</RecommendationAssistCardTitle>
|
||||
<RecommendationShelfInlineBadge>
|
||||
{item.badge}
|
||||
</RecommendationShelfInlineBadge>
|
||||
{item.badge ? (
|
||||
<RecommendationShelfInlineBadge>
|
||||
{item.badge}
|
||||
</RecommendationShelfInlineBadge>
|
||||
) : null}
|
||||
</RecommendationAssistCardHeader>
|
||||
<RecommendationAssistCardSummary>
|
||||
{item.contextSummary
|
||||
@@ -1934,7 +1937,7 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
|
||||
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<EmptyStateProps> = ({
|
||||
<RecommendationAssistCardTitle>
|
||||
{item.title}
|
||||
</RecommendationAssistCardTitle>
|
||||
<RecommendationShelfBadge>{item.badge}</RecommendationShelfBadge>
|
||||
{item.badge ? (
|
||||
<RecommendationShelfBadge>{item.badge}</RecommendationShelfBadge>
|
||||
) : null}
|
||||
</RecommendationAssistCardHeader>
|
||||
<RecommendationAssistCardSummary>
|
||||
{item.summary}
|
||||
|
||||
@@ -846,6 +846,21 @@ export function ImageTaskViewer({
|
||||
src={selectedOutput.url}
|
||||
alt={selectedOutput.prompt || "图片任务结果"}
|
||||
className="h-full w-full object-contain"
|
||||
renderFallback={(reason) => (
|
||||
<div className="flex h-full min-h-[320px] items-center justify-center px-6 text-center">
|
||||
<div className="max-w-sm space-y-3">
|
||||
<Sparkles className="mx-auto h-8 w-8 text-slate-400" />
|
||||
<div className="text-sm font-semibold text-slate-900">
|
||||
{reason === "error" ? "预览加载失败" : "暂无可预览图片"}
|
||||
</div>
|
||||
<div className="text-sm leading-6 text-slate-500">
|
||||
{reason === "error"
|
||||
? "这张图片暂时无法在预览窗口中展示,请稍后重试或在新窗口打开。"
|
||||
: "当前没有可展示的图片结果。"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
{selectedTaskOutputs.length > 1 ? (
|
||||
@@ -926,6 +941,18 @@ export function ImageTaskViewer({
|
||||
"w-full object-cover",
|
||||
resolveOutputTileAspectClass(selectedTask?.layoutHint),
|
||||
)}
|
||||
renderFallback={() => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex w-full items-center justify-center bg-slate-50 px-3 text-center text-[11px] font-medium text-slate-400",
|
||||
resolveOutputTileAspectClass(
|
||||
selectedTask?.layoutHint,
|
||||
),
|
||||
)}
|
||||
>
|
||||
预览失败
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<span className="absolute left-2 top-2 inline-flex h-6 min-w-6 items-center justify-center rounded-full border border-slate-200/80 bg-white/95 px-1.5 text-[11px] font-semibold text-slate-700 shadow-sm shadow-slate-950/5">
|
||||
{resolveOutputDisplayIndex(index, output.slotIndex)}
|
||||
|
||||
@@ -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("这轮复盘更建议优先回到");
|
||||
|
||||
@@ -333,9 +333,11 @@ export const CharacterMentionPanel: React.FC<CharacterMentionPanelProps> = ({
|
||||
<div className="flex flex-wrap items-start justify-between gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-[10px] font-medium text-emerald-700">
|
||||
{section.banner.badge}
|
||||
</span>
|
||||
{section.banner.badge ? (
|
||||
<span className="rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-[10px] font-medium text-emerald-700">
|
||||
{section.banner.badge}
|
||||
</span>
|
||||
) : null}
|
||||
<div className="text-xs font-semibold leading-5 text-slate-900">
|
||||
{section.banner.title}
|
||||
</div>
|
||||
|
||||
@@ -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(
|
||||
[
|
||||
|
||||
@@ -593,7 +593,6 @@ export const ProviderModelList: React.FC<ProviderModelListProps> = ({
|
||||
preservesCurrentProviderCustomModels ||
|
||||
(!autoFetchCapability.requiresLiveModelTruth &&
|
||||
(normalizedSource === "Catalog" ||
|
||||
normalizedSource === "CustomModels" ||
|
||||
normalizedSource === "LocalFallback"));
|
||||
|
||||
if (result && result.models) {
|
||||
|
||||
Reference in New Issue
Block a user