feat: 支持 AI 设计项目多会话交互
需求:用户可在同一设计项目中新建和切换会话,任务列表保持项目级共享。 实现: - 增加会话选择、新建入口及本地数据迁移 - Conversation 独立消息、Brief、Quote 与流式状态 - 保留项目任务并修复 Task revision 与 ABA 异步竞态 - 保持 Enter 发送、Shift+Enter 换行及 IME 保护
This commit is contained in:
@@ -371,8 +371,16 @@ describe('Sidebar project initialization flow', () => {
|
||||
const summary = {
|
||||
workspaceId: 'cloud-project',
|
||||
title: '云端概念设计',
|
||||
turnRevision: 0,
|
||||
viewRevision: 0,
|
||||
conversationCount: 1,
|
||||
phase: 'shaping',
|
||||
updatedAt: '2026-07-31T10:00:00Z',
|
||||
};
|
||||
const conversation = {
|
||||
conversationId: 'cloud-conversation',
|
||||
workspaceId: 'cloud-project',
|
||||
title: '主会话',
|
||||
turnRevision: 0,
|
||||
phase: 'shaping',
|
||||
brief: {
|
||||
version: 0,
|
||||
@@ -382,8 +390,11 @@ describe('Sidebar project initialization flow', () => {
|
||||
ready: false,
|
||||
missingDecision: '作品形式',
|
||||
},
|
||||
createdAt: '2026-07-31T10:00:00Z',
|
||||
updatedAt: '2026-07-31T10:00:00Z',
|
||||
messages: [],
|
||||
};
|
||||
const { messages: _messages, ...conversationSummary } = conversation;
|
||||
const bootstrap = {
|
||||
capabilities: {
|
||||
conversation: true,
|
||||
@@ -398,7 +409,20 @@ describe('Sidebar project initialization flow', () => {
|
||||
return { success: true, data: bootstrap };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/cloud-project' && !init?.method) {
|
||||
return { success: true, data: { ...summary, messages: [] } };
|
||||
return { success: true, data: { ...summary, conversations: [conversationSummary] } };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/cloud-project/conversations/cloud-conversation') {
|
||||
return { success: true, data: conversation };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/cloud-project-two/conversations/cloud-conversation-two') {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
...conversation,
|
||||
workspaceId: 'cloud-project-two',
|
||||
conversationId: 'cloud-conversation-two',
|
||||
},
|
||||
};
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/cloud-project/tasks') {
|
||||
return { success: true, data: [] };
|
||||
@@ -406,7 +430,16 @@ describe('Sidebar project initialization flow', () => {
|
||||
if (path === '/api/works/image-workspace/workspaces' && init?.method === 'POST') {
|
||||
return {
|
||||
success: true,
|
||||
data: { ...summary, workspaceId: 'cloud-project-two', title: '角色设定', messages: [] },
|
||||
data: {
|
||||
...summary,
|
||||
workspaceId: 'cloud-project-two',
|
||||
title: '角色设定',
|
||||
conversations: [{
|
||||
...conversationSummary,
|
||||
workspaceId: 'cloud-project-two',
|
||||
conversationId: 'cloud-conversation-two',
|
||||
}],
|
||||
},
|
||||
};
|
||||
}
|
||||
throw new Error(`Unexpected path ${path}`);
|
||||
@@ -451,8 +484,16 @@ describe('Sidebar project initialization flow', () => {
|
||||
const summary = {
|
||||
workspaceId: 'local-project',
|
||||
title: '概念设计',
|
||||
turnRevision: 0,
|
||||
viewRevision: 0,
|
||||
conversationCount: 1,
|
||||
phase: 'shaping',
|
||||
updatedAt: '2026-07-31T10:00:00Z',
|
||||
};
|
||||
const conversation = {
|
||||
conversationId: 'local-conversation',
|
||||
workspaceId: 'local-project',
|
||||
title: '主会话',
|
||||
turnRevision: 0,
|
||||
phase: 'shaping',
|
||||
brief: {
|
||||
version: 0,
|
||||
@@ -462,8 +503,11 @@ describe('Sidebar project initialization flow', () => {
|
||||
ready: false,
|
||||
missingDecision: '作品形式',
|
||||
},
|
||||
createdAt: '2026-07-31T10:00:00Z',
|
||||
updatedAt: '2026-07-31T10:00:00Z',
|
||||
messages: [],
|
||||
};
|
||||
const { messages: _messages, ...conversationSummary } = conversation;
|
||||
let bootstrap = {
|
||||
capabilities: {
|
||||
conversation: true,
|
||||
@@ -478,7 +522,10 @@ describe('Sidebar project initialization flow', () => {
|
||||
return { success: true, data: bootstrap };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/local-project' && !init?.method) {
|
||||
return { success: true, data: { ...summary, messages: [] } };
|
||||
return { success: true, data: { ...summary, conversations: [conversationSummary] } };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/local-project/conversations/local-conversation') {
|
||||
return { success: true, data: conversation };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/local-project/tasks') {
|
||||
return { success: true, data: [] };
|
||||
@@ -488,11 +535,25 @@ describe('Sidebar project initialization flow', () => {
|
||||
...summary,
|
||||
workspaceId: 'local-project-two',
|
||||
title: '角色设计',
|
||||
messages: [],
|
||||
conversations: [{
|
||||
...conversationSummary,
|
||||
workspaceId: 'local-project-two',
|
||||
conversationId: 'local-conversation-two',
|
||||
}],
|
||||
};
|
||||
bootstrap = { ...bootstrap, workspaces: [created, ...bootstrap.workspaces] };
|
||||
return { success: true, data: created };
|
||||
}
|
||||
if (path === '/api/works/image-workspace/workspaces/local-project-two/conversations/local-conversation-two') {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
...conversation,
|
||||
workspaceId: 'local-project-two',
|
||||
conversationId: 'local-conversation-two',
|
||||
},
|
||||
};
|
||||
}
|
||||
throw new Error(`Unexpected path ${path}`);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user