feat(teacher): stream Yuxi reasoning and answer previews
This commit is contained in:
@@ -26,6 +26,8 @@ type ConsultationReply = {
|
||||
suggestedQuestions: string[];
|
||||
replyParseError?: string;
|
||||
unparsedResponse?: string;
|
||||
status?: 'running' | 'completed';
|
||||
reasoning?: string;
|
||||
};
|
||||
|
||||
type TeacherCatalogFixture = {
|
||||
@@ -2575,3 +2577,56 @@ test('work failure offers a useful recovery and retains the student draft after
|
||||
expect(new Set(opens.map((item) => item.body?.request_id)).size).toBe(2);
|
||||
expect(requests.filter((item) => item.path.endsWith('/prompt'))).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('teacher reasoning and answer stream separately before the final response', async ({ launchElectronApp }) => {
|
||||
const app = await launchElectronApp({ skipSetup: true });
|
||||
let page = await getStableWindow(app);
|
||||
const connection = await page.evaluate(async () => ({
|
||||
token: await window.electron.ipcRenderer.invoke('hostapi:token') as string,
|
||||
baseUrl: await window.electron.ipcRenderer.invoke('hostapi:base-url') as string,
|
||||
}));
|
||||
await installCodingFirstChatHost(app, connection, true, false, false, undefined, false, {
|
||||
response: '', suggestedQuestions: [], status: 'running', reasoning: '先观察项目代码。',
|
||||
});
|
||||
await settleSnapshot(app);
|
||||
await disableCodingEventSource(page);
|
||||
try {
|
||||
await page.reload(); page = await getStableWindow(app);
|
||||
await page.getByTestId('ai-module-option-programming').click();
|
||||
await page.evaluate(() => { window.location.hash = '/chat'; });
|
||||
await page.getByRole('button', { name: '与代码智能体聊天', exact: true }).click();
|
||||
const teacher = page.getByTestId('teacher-chat-panel');
|
||||
await teacher.getByRole('textbox', { name: '向智能体提问' }).fill('帮我看看项目');
|
||||
await teacher.getByRole('button', { name: '提问', exact: true }).click();
|
||||
const reasoning = teacher.getByTestId('teacher-reasoning');
|
||||
await expect(reasoning).toHaveAttribute('open');
|
||||
await expect(reasoning.getByText('先观察项目代码。', { exact: true })).toBeVisible();
|
||||
await expect(teacher.getByTestId('teacher-reply')).toHaveCount(0);
|
||||
const send = (await readState(app)).captured.find(item => item.path.endsWith('/messages') && item.method === 'POST')!;
|
||||
const current = await page.evaluate(async path => {
|
||||
const result = await window.electron.ipcRenderer.invoke('hostapi:fetch', { path, method: 'GET' }) as {
|
||||
data: { json: { topic: import('../../shared/coding-teacher').TeacherTopic } };
|
||||
};
|
||||
return result.data.json.topic;
|
||||
}, send.path.replace(/\/messages$/, ''));
|
||||
current.requests[0].reasoning += '再检查交互。'; current.revision++;
|
||||
await emitCodingEvent(page, 'snapshot', current);
|
||||
await expect(reasoning).toContainText('先观察项目代码。再检查交互。');
|
||||
current.requests[0].response = '可以先'; current.revision++;
|
||||
await emitCodingEvent(page, 'snapshot', current);
|
||||
await expect(teacher.getByTestId('teacher-reply')).toHaveText('可以先');
|
||||
await expect(teacher.getByRole('button', { name: '停止回复', exact: true })).toBeVisible();
|
||||
current.requests[0].response = '可以先观察玩家反馈。'; current.revision++;
|
||||
await emitCodingEvent(page, 'snapshot', current);
|
||||
await expect(teacher.getByTestId('teacher-reply')).toHaveText('可以先观察玩家反馈。');
|
||||
await teacher.screenshot({ path: test.info().outputPath('teacher-streaming.png') });
|
||||
current.requests[0].status = 'completed'; current.requests[0].suggestedQuestions = ['怎么观察?']; current.revision++;
|
||||
await emitCodingEvent(page, 'snapshot', current);
|
||||
await expect(reasoning).not.toHaveAttribute('open');
|
||||
await reasoning.locator('summary').click();
|
||||
await expect(reasoning.getByLabel('智能体思考过程')).toBeVisible();
|
||||
await expect(teacher.getByRole('button', { name: '怎么观察?', exact: true })).toBeVisible();
|
||||
await expect(teacher.getByTestId('teacher-reply')).not.toContainText('检查交互');
|
||||
expect((await readState(app)).captured.filter(item => item.path.endsWith('/messages') && item.method === 'POST')).toHaveLength(1);
|
||||
} finally { await releaseSnapshot(app); }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user