合并 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

@@ -11,6 +11,7 @@ import {
IMAGE_WORKSPACE_UNAVAILABLE_CODE,
IMAGE_WORKSPACE_UNAVAILABLE_MESSAGE,
type DesignAssetUploadInput,
type DesignCreateConversationInput,
type DesignConfirmGenerationInput,
type DesignCreateWorkspaceInput,
type DesignRenameWorkspaceInput,
@@ -283,6 +284,7 @@ async function relayWorkspaceEvents(
res: ServerResponse,
ctx: HostApiContext,
workspaceId: string,
conversationId: string,
): Promise<void> {
if (!ctx.imageWorkspace?.openWorkspaceEvents) {
throw new DesignWorkspaceModuleError(
@@ -295,6 +297,7 @@ async function relayWorkspaceEvents(
const afterEventId = Array.isArray(header) ? header[0] : header;
const subscription = await ctx.imageWorkspace.openWorkspaceEvents({
workspaceId,
conversationId,
...(afterEventId ? { afterEventId } : {}),
});
let closed = false;
@@ -399,11 +402,35 @@ export async function handleImageWorkspaceRoutes(
if (segments.length === 3
&& segments[0] === 'workspaces'
&& segments[2] === 'messages'
&& segments[2] === 'conversations'
&& req.method === 'POST') {
const body = await parseJsonBody<Record<string, unknown>>(req);
const input: DesignCreateConversationInput = {
workspaceId: segments[1],
clientConversationId: asString(body.clientConversationId),
title: asString(body.title),
};
sendData(res, await ctx.imageWorkspace.createConversation(input));
return true;
}
if (segments.length === 4
&& segments[0] === 'workspaces'
&& segments[2] === 'conversations'
&& req.method === 'GET') {
sendData(res, await ctx.imageWorkspace.getConversation(segments[1], segments[3]));
return true;
}
if (segments.length === 5
&& segments[0] === 'workspaces'
&& segments[2] === 'conversations'
&& segments[4] === 'messages'
&& req.method === 'POST') {
const body = await parseJsonBody<Record<string, unknown>>(req);
const input: DesignSubmitMessageInput = {
workspaceId: segments[1],
conversationId: segments[3],
clientTurnId: asString(body.clientTurnId),
expectedTurnRevision: asInteger(body.expectedTurnRevision),
message: asString(body.message),
@@ -440,23 +467,26 @@ export async function handleImageWorkspaceRoutes(
return true;
}
if (segments.length === 3
if (segments.length === 5
&& segments[0] === 'workspaces'
&& segments[2] === 'events'
&& segments[2] === 'conversations'
&& segments[4] === 'events'
&& req.method === 'GET') {
await relayWorkspaceEvents(req, res, ctx, segments[1]);
await relayWorkspaceEvents(req, res, ctx, segments[1], segments[3]);
return true;
}
if (segments.length === 5
if (segments.length === 7
&& segments[0] === 'workspaces'
&& segments[2] === 'quotes'
&& segments[4] === 'confirm'
&& segments[2] === 'conversations'
&& segments[4] === 'quotes'
&& segments[6] === 'confirm'
&& req.method === 'POST') {
const body = await parseJsonBody<Record<string, unknown>>(req);
const input: DesignConfirmGenerationInput = {
workspaceId: segments[1],
quoteId: segments[3],
conversationId: segments[3],
quoteId: segments[5],
clientTurnId: asString(body.clientTurnId),
expectedTurnRevision: asInteger(body.expectedTurnRevision),
};