refactor(admin): A2UI 双轨收敛,统一 artifact 协议

- mergeArtifactIntoMessage 不再派发 legacy 列表,只维护 uiArtifacts
- 渲染层从 uiArtifacts 派生 forms/reviews/charts,为空时回退 legacy
  (历史消息兼容,老 metadata 仅 a2uiForm/a2uiReview/a2uiChart)
- sseReducer 删除 ui.form/ui.review/ui.chart 旧事件分支,只消费
  ui.artifact(后端过渡期双发,旧事件将被忽略)
- types.ts legacy 字段标注 deprecated;契约文档同步现状
- 测试更新:旧事件忽略 + uiArtifacts 合并/恢复断言

aislop scan: 5 引擎 0 issues
This commit is contained in:
2026-08-08 09:33:53 +08:00
parent a644a8de42
commit bcd2d1a559
7 changed files with 98 additions and 79 deletions

View File

@@ -17,6 +17,7 @@ import { message } from '../../ui/app-message';
import { DynamicChart } from './DynamicChart';
import { DynamicForm } from './DynamicForm';
import { DynamicReview } from './DynamicReview';
import { deriveCharts, deriveForms, deriveReviews } from './uiArtifacts';
import { ArtifactErrorBoundary } from './ArtifactErrorBoundary';
import { LiteCodeHighlighter } from './LiteCodeHighlighter';
import { LiteMermaid } from './LiteMermaid';
@@ -226,6 +227,11 @@ export const AiMessageContent: React.FC<AiMessageContentProps> = ({
const streaming = status === 'loading' || status === 'updating';
const formSubmission = message.metadata?.a2uiSubmit;
const reviewSubmission = message.metadata?.a2uiReviewSubmit;
// 统一 artifact 优先,历史消息(仅 legacy 字段)回退
const forms = deriveForms(message).length > 0 ? deriveForms(message) : (message.forms ?? []);
const reviews =
deriveReviews(message).length > 0 ? deriveReviews(message) : (message.reviews ?? []);
const charts = deriveCharts(message).length > 0 ? deriveCharts(message) : (message.charts ?? []);
const sourceMeta = message.metadata?.a2uiSources;
const sourceItems = Array.isArray(sourceMeta)
? sourceMeta
@@ -374,7 +380,7 @@ export const AiMessageContent: React.FC<AiMessageContentProps> = ({
onClick={(item) => void handleOpenSource(item as { url?: string })}
/>
)}
{(message.forms ?? []).map((form) => (
{(forms ?? []).map((form) => (
<ArtifactErrorBoundary key={form.id} title="表单">
<DynamicForm
form={form}
@@ -383,7 +389,7 @@ export const AiMessageContent: React.FC<AiMessageContentProps> = ({
/>
</ArtifactErrorBoundary>
))}
{(message.reviews ?? []).map((review: AiReviewSchema) => (
{(reviews ?? []).map((review: AiReviewSchema) => (
<ArtifactErrorBoundary key={review.id} title="导入预览">
<DynamicReview
review={review}
@@ -395,7 +401,7 @@ export const AiMessageContent: React.FC<AiMessageContentProps> = ({
/>
</ArtifactErrorBoundary>
))}
{(message.charts ?? []).map((chart: AiChartSchema) => (
{(charts ?? []).map((chart: AiChartSchema) => (
<ArtifactErrorBoundary key={chart.id} title="图表">
<DynamicChart chart={chart} />
</ArtifactErrorBoundary>