feat(design): integrate agent activity timeline
This commit is contained in:
@@ -198,6 +198,63 @@ describe('youth AI Design Canvas page', () => {
|
||||
.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps each pending reply beside the user message that started it', () => {
|
||||
prepareWorkspace({ turns: [] });
|
||||
useImageWorkspaceStore.setState({
|
||||
pendingOperations: {
|
||||
'operation-chat-1': {
|
||||
id: 'operation-chat-1',
|
||||
label: '发送创作想法',
|
||||
command: {
|
||||
kind: 'apply_input',
|
||||
workspaceId: 'workspace-1',
|
||||
sessionId: 'session-1',
|
||||
expectedDirectionRevision: 4,
|
||||
clientOperationId: 'operation-chat-1',
|
||||
input: { kind: 'chat', message: '先画一只小熊' },
|
||||
},
|
||||
status: 'unknown',
|
||||
error: '结果尚未确认',
|
||||
clearDraftPaths: [],
|
||||
clearChatDraft: true,
|
||||
baseRawTurnSequence: 1,
|
||||
},
|
||||
'operation-chat-2': {
|
||||
id: 'operation-chat-2',
|
||||
label: '发送创作想法',
|
||||
command: {
|
||||
kind: 'apply_input',
|
||||
workspaceId: 'workspace-1',
|
||||
sessionId: 'session-1',
|
||||
expectedDirectionRevision: 4,
|
||||
clientOperationId: 'operation-chat-2',
|
||||
input: { kind: 'chat', message: '再补充一只小兔子' },
|
||||
},
|
||||
status: 'submitting',
|
||||
error: null,
|
||||
clearDraftPaths: [],
|
||||
clearChatDraft: true,
|
||||
baseRawTurnSequence: 1,
|
||||
},
|
||||
},
|
||||
assistantStreams: {
|
||||
'operation-chat-1': '小熊会站在月亮旁边。',
|
||||
},
|
||||
});
|
||||
|
||||
render(<ImageCanvas />);
|
||||
|
||||
const conversation = screen.getByTestId('image-workspace-conversation');
|
||||
const firstMessage = within(conversation).getByTestId('pending-design-chat-operation-chat-1');
|
||||
const firstReply = within(conversation)
|
||||
.getByTestId('streaming-design-assistant-operation-chat-1');
|
||||
const secondMessage = within(conversation).getByTestId('pending-design-chat-operation-chat-2');
|
||||
expect(firstMessage.compareDocumentPosition(firstReply) & Node.DOCUMENT_POSITION_FOLLOWING)
|
||||
.toBeTruthy();
|
||||
expect(firstReply.compareDocumentPosition(secondMessage) & Node.DOCUMENT_POSITION_FOLLOWING)
|
||||
.toBeTruthy();
|
||||
});
|
||||
|
||||
it('shows public AI activity under the submitted message and collapses it beside the final turn', async () => {
|
||||
const message = '画一只在月球踢球的熊猫';
|
||||
const { workspace } = prepareWorkspace({ turns: [] });
|
||||
|
||||
@@ -1206,6 +1206,64 @@ describe('V2 Living Form store', () => {
|
||||
.toMatchObject({ status: 'unknown', steps: [{ stage: 'reviewing_context' }] });
|
||||
});
|
||||
|
||||
it('preserves an earlier unknown activity when another chat starts', async () => {
|
||||
await loadedStore();
|
||||
const submission = deferred<Awaited<ReturnType<typeof submitImageWorkspaceCommand>>>();
|
||||
operationIdMock.mockReturnValueOnce('operation-chat-2');
|
||||
submitCommandMock.mockReturnValueOnce(submission.promise);
|
||||
useImageWorkspaceStore.setState({
|
||||
chatDraft: '再补充一只小兔子',
|
||||
pendingOperations: {
|
||||
'operation-chat-1': {
|
||||
id: 'operation-chat-1',
|
||||
label: '发送创作想法',
|
||||
command: {
|
||||
kind: 'apply_input',
|
||||
workspaceId: 'workspace-1',
|
||||
sessionId: 'session-1',
|
||||
expectedDirectionRevision: 4,
|
||||
clientOperationId: 'operation-chat-1',
|
||||
input: { kind: 'chat', message: '先画一只小熊' },
|
||||
},
|
||||
status: 'unknown',
|
||||
error: '结果尚未确认',
|
||||
clearDraftPaths: [],
|
||||
clearChatDraft: true,
|
||||
baseRawTurnSequence: 1,
|
||||
},
|
||||
},
|
||||
assistantActivities: {
|
||||
'operation-chat-1': {
|
||||
workspaceId: 'workspace-1',
|
||||
directionId: 'direction-1',
|
||||
status: 'unknown',
|
||||
turnId: null,
|
||||
steps: [{ stage: 'reviewing_context', message: '正在整理上下文' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const sendPromise = useImageWorkspaceStore.getState().sendChat();
|
||||
|
||||
expect(useImageWorkspaceStore.getState().assistantActivities).toMatchObject({
|
||||
'operation-chat-1': {
|
||||
status: 'unknown',
|
||||
steps: [{ stage: 'reviewing_context' }],
|
||||
},
|
||||
});
|
||||
expect(useImageWorkspaceStore.getState().pendingOperations).toMatchObject({
|
||||
'operation-chat-1': { status: 'unknown' },
|
||||
'operation-chat-2': { status: 'submitting' },
|
||||
});
|
||||
|
||||
submission.resolve({
|
||||
clientOperationId: 'operation-chat-2',
|
||||
runId: 'run-2',
|
||||
workspace: designWorkspaceFixture(),
|
||||
});
|
||||
await sendPromise;
|
||||
});
|
||||
|
||||
it('expires quote blockers only after the canonical Specification changes', async () => {
|
||||
await loadedStore();
|
||||
const blocker = {
|
||||
|
||||
Reference in New Issue
Block a user