合并 AI 设计多会话客户端
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled

整合 Enter 发送与多会话交互,保留服务端持久 Conversation Session,并补齐迁移、回归、Electron E2E 与 canonical 文档。
This commit is contained in:
2026-08-11 16:18:52 +08:00
32 changed files with 2417 additions and 804 deletions

View File

@@ -8,8 +8,10 @@ import {
} from '@/lib/host-api';
import {
confirmImageWorkspaceGeneration,
createImageWorkspaceConversation,
createImageWorkspaceProject,
fetchImageWorkspace,
fetchImageWorkspaceConversation,
ImageWorkspaceApiError,
openImageWorkspaceTaskEvents,
resolveImageWorkspaceAssetUrl,
@@ -59,11 +61,11 @@ describe('AI design renderer API boundary', () => {
});
it('opens task events only after the local Host API token is ready', async () => {
const source = await openImageWorkspaceTaskEvents('workspace/one');
const source = await openImageWorkspaceTaskEvents('workspace/one', 'conversation/one');
expect(source).toBe(createHostEventSourceMock.mock.results[0].value);
expect(createHostEventSourceMock).toHaveBeenCalledWith(
'/api/works/image-workspace/workspaces/workspace%2Fone/events',
'/api/works/image-workspace/workspaces/workspace%2Fone/conversations/conversation%2Fone/events',
);
expect(ensureHostApiTokenMock.mock.invocationCallOrder[0])
.toBeLessThan(createHostEventSourceMock.mock.invocationCallOrder[0]);
@@ -81,16 +83,43 @@ describe('AI design renderer API boundary', () => {
});
});
it('creates and reads Conversations through encoded Main-owned routes', async () => {
await createImageWorkspaceConversation(
'workspace/one',
' 第二会话 ',
'client-conversation-one',
);
await fetchImageWorkspaceConversation('workspace/one', 'conversation/one');
expect(hostApiFetchMock).toHaveBeenNthCalledWith(
1,
'/api/works/image-workspace/workspaces/workspace%2Fone/conversations',
{
method: 'POST',
body: JSON.stringify({
clientConversationId: 'client-conversation-one',
title: '第二会话',
}),
},
);
expect(hostApiFetchMock).toHaveBeenNthCalledWith(
2,
'/api/works/image-workspace/workspaces/workspace%2Fone/conversations/conversation%2Fone',
{},
);
});
it('sends conversation turns with the current turn revision and no provider settings', async () => {
await sendImageWorkspaceMessage(
'workspace/one',
'conversation/one',
4,
' 继续调整构图 ',
'turn-client-1',
);
const [path, init] = hostApiFetchMock.mock.calls[0];
expect(path).toBe('/api/works/image-workspace/workspaces/workspace%2Fone/messages');
expect(path).toBe('/api/works/image-workspace/workspaces/workspace%2Fone/conversations/conversation%2Fone/messages');
expect(init).toMatchObject({ method: 'POST' });
expect(JSON.parse(String(init?.body))).toMatchObject({
expectedTurnRevision: 4,
@@ -104,6 +133,7 @@ describe('AI design renderer API boundary', () => {
it('sends the selected first-frame Asset id with the conversation turn', async () => {
await sendImageWorkspaceMessage(
'workspace-one',
'conversation-one',
5,
'使用作品图片作为视频首帧',
'turn-first-frame',
@@ -148,11 +178,11 @@ describe('AI design renderer API boundary', () => {
});
it('confirms a Quote through a separate structured action route', async () => {
await confirmImageWorkspaceGeneration('workspace-one', 5, 'quote/one');
await confirmImageWorkspaceGeneration('workspace-one', 'conversation-one', 5, 'quote/one');
const [path, init] = hostApiFetchMock.mock.calls[0];
expect(path).toBe(
'/api/works/image-workspace/workspaces/workspace-one/quotes/quote%2Fone/confirm',
'/api/works/image-workspace/workspaces/workspace-one/conversations/conversation-one/quotes/quote%2Fone/confirm',
);
expect(JSON.parse(String(init?.body))).toMatchObject({
expectedTurnRevision: 5,