fix(pi): recover from Works prompt rejection

This commit is contained in:
2026-08-25 14:50:10 +08:00
parent 4580568384
commit 5f0ef761ea
9 changed files with 439 additions and 31 deletions

View File

@@ -519,6 +519,49 @@ describe('CodingChatPanel first Conversation', () => {
expect(screen.getByRole('button', { name: '发送' })).toBeEnabled();
});
it('reenables the same Conversation after a definite prompt rejection', async () => {
projectApi.list.mockResolvedValue({ projects: [project], activeProjectId: project.id });
projectApi.config.mockResolvedValue({ project, config });
projectApi.conversations.mockResolvedValue([conversation]);
conversationApi.events.mockResolvedValue(new FakeEventSource() as unknown as EventSource);
conversationApi.recover.mockResolvedValue(undefined);
conversationApi.submit
.mockRejectedValueOnce(new Error('所选模型当前不可用,请重新选择。'))
.mockImplementationOnce(async (input: {
conversationId: string;
clientRequestId: string;
mode: 'prompt';
}) => ({
accepted: true,
conversationId: input.conversationId,
clientRequestId: input.clientRequestId,
runId: 'run-retry',
mode: input.mode,
}));
const { CodingChatPanel } = await import('@/pages/Chat/CodingChatPanel');
const { createLocalConversationSnapshot } = await import('@/pages/Chat/coding-chat-snapshot');
const { codingConversationStore } = await import('@/stores/coding-conversations');
conversationApi.snapshot.mockResolvedValue(createLocalConversationSnapshot(project.id, conversation));
render(<CodingChatPanel />);
const textbox = await screen.findByRole('textbox');
await waitFor(() => expect(codingConversationStore.getState().selectedConversationId)
.toBe(conversation.id));
fireEvent.change(textbox, { target: { value: 'First prompt' } });
await waitFor(() => expect(screen.getByRole('button', { name: '发送' })).toBeEnabled());
fireEvent.click(screen.getByRole('button', { name: '发送' }));
await waitFor(() => expect(textbox).toHaveValue('First prompt'));
expect(await screen.findByText('所选模型当前不可用,请重新选择。')).toBeInTheDocument();
expect(codingConversationStore.getState().entriesByConversationId[conversation.id]?.error)
.toBeNull();
expect(screen.queryByRole('button', { name: '重试' })).not.toBeInTheDocument();
fireEvent.change(textbox, { target: { value: 'Retry prompt' } });
await waitFor(() => expect(screen.getByRole('button', { name: '发送' })).toBeEnabled());
fireEvent.click(screen.getByRole('button', { name: '发送' }));
await waitFor(() => expect(conversationApi.submit).toHaveBeenCalledTimes(2));
});
it('caps one message at 16 images and uploads at most four concurrently', async () => {
projectApi.list.mockResolvedValue({ projects: [project], activeProjectId: project.id });
projectApi.config.mockResolvedValue({ project, config });