feat: 支持 AI 设计项目多会话交互
需求:用户可在同一设计项目中新建和切换会话,任务列表保持项目级共享。 实现: - 增加会话选择、新建入口及本地数据迁移 - Conversation 独立消息、Brief、Quote 与流式状态 - 保留项目任务并修复 Task revision 与 ABA 异步竞态 - 保持 Enter 发送、Shift+Enter 换行及 IME 保护
This commit is contained in:
@@ -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),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user