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:
@@ -123,38 +123,35 @@ describe('AI chat SSE message reducer', () => {
|
||||
expect(message.id).toBe(9);
|
||||
});
|
||||
|
||||
it('merges ui.form events into the assistant message by id', () => {
|
||||
const form = {
|
||||
id: 'form-1',
|
||||
title: '新增学生',
|
||||
submitLabel: '提交创建',
|
||||
fields: [
|
||||
{ name: 'name', label: '姓名', type: 'input', required: true },
|
||||
{ name: 'gender', label: '性别', type: 'select', options: [{ label: '男', value: 'male' }] },
|
||||
],
|
||||
};
|
||||
it('ignores legacy ui.form events and only consumes ui.artifact (过渡期双发)', () => {
|
||||
let message = reduceAiSseMessage(undefined, {
|
||||
event: 'ui.form',
|
||||
data: JSON.stringify({ messageId: 8, form }),
|
||||
data: JSON.stringify({ messageId: 8, form: { id: 'form-1', title: '新增学生', fields: [] } }),
|
||||
});
|
||||
// 旧事件不再写入 legacy 列表
|
||||
expect(message.forms).toHaveLength(0);
|
||||
expect(message.uiArtifacts).toHaveLength(0);
|
||||
|
||||
message = reduceAiSseMessage(message, {
|
||||
event: 'ui.form',
|
||||
data: JSON.stringify({ messageId: 8, form: { ...form, id: 'form-1' } }),
|
||||
});
|
||||
message = reduceAiSseMessage(message, {
|
||||
event: 'ui.form',
|
||||
event: 'ui.artifact',
|
||||
data: JSON.stringify({
|
||||
messageId: 8,
|
||||
form: { id: 'form-2', title: '入住确认', fields: [] },
|
||||
artifact: {
|
||||
id: 'form-1',
|
||||
type: 'form',
|
||||
status: 'pending',
|
||||
messageId: 8,
|
||||
conversationId: 3,
|
||||
payload: { id: 'form-1', title: '新增学生', fields: [] },
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
expect(message.forms).toHaveLength(2);
|
||||
expect(message.forms?.[0]).toMatchObject({ id: 'form-1', title: '新增学生' });
|
||||
expect(message.forms?.[1]).toMatchObject({ id: 'form-2' });
|
||||
expect(message.uiArtifacts).toHaveLength(1);
|
||||
expect(message.uiArtifacts?.[0].payload).toMatchObject({ id: 'form-1', title: '新增学生' });
|
||||
});
|
||||
|
||||
it('merges ui.artifact events into uiArtifacts and legacy lists by id', () => {
|
||||
it('merges ui.artifact events into uiArtifacts by id', () => {
|
||||
let message = reduceAiSseMessage(undefined, {
|
||||
event: 'ui.artifact',
|
||||
data: JSON.stringify({
|
||||
@@ -185,8 +182,8 @@ describe('AI chat SSE message reducer', () => {
|
||||
});
|
||||
|
||||
expect(message.uiArtifacts).toHaveLength(2);
|
||||
expect(message.forms?.[0]).toMatchObject({ id: 'form-1', title: '新增学生' });
|
||||
expect(message.reviews?.[0]).toMatchObject({ id: 'review-1', status: 'expired' });
|
||||
expect(message.uiArtifacts?.[0].payload).toMatchObject({ id: 'form-1', title: '新增学生' });
|
||||
expect(message.uiArtifacts?.[1].payload).toMatchObject({ id: 'review-1', status: 'expired' });
|
||||
});
|
||||
|
||||
|
||||
@@ -213,7 +210,7 @@ describe('AI chat SSE message reducer', () => {
|
||||
expect(message.forms?.[0].id).toBe('form-9');
|
||||
});
|
||||
|
||||
it('merges ui.review events into the assistant message and updates by id', () => {
|
||||
it('ignores legacy ui.review events and only consumes ui.artifact', () => {
|
||||
const review = {
|
||||
id: 'review-1',
|
||||
title: '开学导入',
|
||||
@@ -246,8 +243,9 @@ describe('AI chat SSE message reducer', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
expect(message.reviews).toHaveLength(1);
|
||||
expect(message.reviews?.[0]).toMatchObject({ id: 'review-1', status: 'submitted' });
|
||||
// 旧事件不再写入 legacy 列表
|
||||
expect(message.reviews).toBeUndefined();
|
||||
expect(message.uiArtifacts).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows model retrying state and clears it when content starts', () => {
|
||||
@@ -301,7 +299,7 @@ describe('AI chat SSE message reducer', () => {
|
||||
expect(message.reviews?.[0]).toMatchObject({ id: 'review-9', title: '批量导入' });
|
||||
});
|
||||
|
||||
it('merges ui.chart events into the assistant message by id', () => {
|
||||
it('ignores legacy ui.chart events and only consumes ui.artifact', () => {
|
||||
const chart = {
|
||||
id: 'chart-1',
|
||||
title: '各班级人数',
|
||||
@@ -327,9 +325,9 @@ describe('AI chat SSE message reducer', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
expect(message.charts).toHaveLength(2);
|
||||
expect(message.charts?.[0]).toMatchObject({ id: 'chart-1', chartType: 'bar' });
|
||||
expect(message.charts?.[1]).toMatchObject({ id: 'chart-2' });
|
||||
// 旧事件不再写入 legacy 列表
|
||||
expect(message.charts).toBeUndefined();
|
||||
expect(message.uiArtifacts).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('restores persisted charts from message.completed metadata', () => {
|
||||
|
||||
Reference in New Issue
Block a user