fix(teacher): 隔离子智能体流式消息与老师正文

This commit is contained in:
2026-09-23 10:25:43 +08:00
parent 3fe98fc565
commit d20c818fe7
4 changed files with 73 additions and 7 deletions

View File

@@ -257,10 +257,13 @@ it('reconnects from the last cursor and fills the final message after an earlier
const transport: TeacherCloudTransport = {
json: vi.fn(async (url) => {
if (url === '/questions') return { request_id: 'question', run_id: 'one' };
return ++reads < 3 ? { status: 'running' } : { status: 'completed', output: '最终建议' };
return ++reads < 3
? { status: 'running', thread_id: 'teacher-thread' }
: { status: 'completed', output: '最终建议' };
}),
events: vi.fn(async (url, _signal, accept) => {
const message = (id: string, content: string) => ({
thread_id: 'teacher-thread',
payload: { items: [{ stream_event: { type: 'message_delta', message_id: id, content } }] },
});
if (++streams === 1) {
@@ -285,3 +288,62 @@ it('reconnects from the last cursor and fills the final message after an earlier
expect(text.join('')).toBe('我先检查。\n\n最终建议');
expect(f.progress).toHaveBeenCalledWith('连接中断,正在恢复老师回复…');
});
it('keeps only the cloud main-thread answer while advancing past child events on reconnect', async () => {
const f = await fixture();
let reads = 0;
let streams = 0;
const text: string[] = [];
const streamUrls: string[] = [];
const transport: TeacherCloudTransport = {
json: vi.fn(async (url) => {
if (url === '/questions') return { request_id: 'question', run_id: 'one' };
return ++reads < 3
? { status: 'running', thread_id: 'teacher-thread' }
: { status: 'completed', output: '老师最终答复' };
}),
events: vi.fn(async (url, _signal, accept) => {
streamUrls.push(url);
const message = (threadId: string, id: string, content: string) => ({
thread_id: threadId,
payload: { items: [{ stream_event: { type: 'message_delta', message_id: id, content } }] },
});
if (++streams === 1) {
accept('message', message('teacher-thread', 'answer', '老师'), '1-0');
accept('message', message('child-thread', 'child-answer', '子智能体内容'), '2-0');
throw new Error('connection interrupted');
}
accept(
'message',
{
thread_id: 'child-thread',
payload: {
chunk: {
stream_event: {
type: 'message_delta',
message_id: 'child-answer',
content: '子智能体后续内容',
},
},
},
},
'3-0'
);
accept('message', message('teacher-thread', 'answer', '最终答复'), '4-0');
}),
};
await prepareCloudTeacher(
f.account,
f.topic,
requestId,
f.access,
f.progress,
f.saveRequest,
transport
).run([{ role: 'user', content: '检查' }], new AbortController().signal, (delta) =>
text.push(delta)
);
expect(text.join('')).toBe('老师最终答复');
expect(transport.events).toHaveBeenCalledTimes(2);
expect(streamUrls[1]).toContain('after_seq=2-0');
});