forked from wangziqi/gongxue-base
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:
@@ -25,43 +25,49 @@ export function mergeById<T extends { id: string }>(
|
||||
return next;
|
||||
}
|
||||
|
||||
export function mergeForms(
|
||||
current: AiFormSchema[] | undefined,
|
||||
incoming: AiFormSchema | AiFormSchema[] | undefined,
|
||||
): AiFormSchema[] {
|
||||
const items = Array.isArray(incoming) ? incoming : incoming ? [incoming] : [];
|
||||
if (!items.length) return current ?? [];
|
||||
const next = [...(current ?? [])];
|
||||
for (const item of items) {
|
||||
if (item && typeof item === 'object' && !next.some((existing) => existing.id === item.id)) {
|
||||
next.push(item);
|
||||
}
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
function payloadOf(artifact: AiArtifactSchema): unknown {
|
||||
return artifact.payload && typeof artifact.payload === 'object' ? artifact.payload : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将统一 artifact 归入 uiArtifacts,并按类型派发到 legacy 列表。
|
||||
* payload 来自服务端契约(表单/审阅/图表/预检/向导),按类型做单次断言。
|
||||
* 将统一 artifact 归入 uiArtifacts。
|
||||
*
|
||||
* 注意:不再派发到 legacy 列表(forms/reviews/charts)——渲染层从
|
||||
* uiArtifacts 派生,legacy 字段仅保留给历史消息(metadata 中只有
|
||||
* a2uiForm/a2uiReview/a2uiChart 的老数据)作兼容读取。
|
||||
*/
|
||||
export function mergeArtifactIntoMessage(
|
||||
message: AiChatMessage,
|
||||
artifact: AiArtifactSchema,
|
||||
): AiChatMessage {
|
||||
message.uiArtifacts = mergeById<AiArtifactSchema>(message.uiArtifacts, artifact);
|
||||
const payload = payloadOf(artifact);
|
||||
if (artifact.type === 'form') {
|
||||
message.forms = mergeForms(message.forms, payload as AiFormSchema);
|
||||
} else if (artifact.type === 'review') {
|
||||
message.reviews = mergeById<AiReviewSchema>(message.reviews, payload as AiReviewSchema);
|
||||
} else if (artifact.type === 'chart') {
|
||||
message.charts = mergeById<AiChartSchema>(message.charts, payload as AiChartSchema);
|
||||
} else if (artifact.type === 'import_wizard') {
|
||||
message.metadata = { ...message.metadata, a2uiImportWizard: payload };
|
||||
}
|
||||
void payloadOf(artifact);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 uiArtifacts 派生 legacy 列表(渲染用)。
|
||||
* 仅当 message 上没有显式 legacy 数据(历史消息)时,渲染层回退到 message.forms 等。
|
||||
*/
|
||||
export function deriveForms(message: AiChatMessage): AiFormSchema[] {
|
||||
return (message.uiArtifacts ?? [])
|
||||
.filter((artifact) => artifact.type === 'form')
|
||||
.map((artifact) => artifact.payload)
|
||||
.filter((payload): payload is AiFormSchema => Boolean(payload) && typeof payload === 'object');
|
||||
}
|
||||
|
||||
export function deriveReviews(message: AiChatMessage): AiReviewSchema[] {
|
||||
return (message.uiArtifacts ?? [])
|
||||
.filter((artifact) => artifact.type === 'review')
|
||||
.map((artifact) => artifact.payload)
|
||||
.filter(
|
||||
(payload): payload is AiReviewSchema => Boolean(payload) && typeof payload === 'object',
|
||||
);
|
||||
}
|
||||
|
||||
export function deriveCharts(message: AiChatMessage): AiChartSchema[] {
|
||||
return (message.uiArtifacts ?? [])
|
||||
.filter((artifact) => artifact.type === 'chart')
|
||||
.map((artifact) => artifact.payload)
|
||||
.filter((payload): payload is AiChartSchema => Boolean(payload) && typeof payload === 'object');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user