fix: render consultation replies and typed tool activity
This commit is contained in:
@@ -113,6 +113,44 @@ it('submits only the published persona, source evidence and current question in
|
||||
expect(body.local_context.tools).toEqual(['list_project_files', 'read_project_file', 'read_conversation']);
|
||||
});
|
||||
|
||||
it.each([null, { content: 'not a supported output field' }, ['text block']])('reports unsupported final output instead of silently losing %j', async output => {
|
||||
const f = await fixture();
|
||||
const text = vi.fn();
|
||||
const transport: TeacherCloudTransport = {
|
||||
json: vi.fn(async url => url === '/questions' ? { request_id: requestId, run_id: 'run' } : { status: 'completed', output }),
|
||||
events: vi.fn(),
|
||||
};
|
||||
await expect(prepareCloudTeacher(f.account, f.topic, requestId, f.access, f.progress, f.saveRequest, transport)
|
||||
.run([{ role: 'user', content: '问题' }], new AbortController().signal, text))
|
||||
.rejects.toMatchObject({ code: 'teacher_protocol_invalid' });
|
||||
expect(text).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('merges typed tool activity across replay without adding tool data or child events to the answer', async () => {
|
||||
const f = await fixture();
|
||||
let reads = 0;
|
||||
const activity = vi.fn(), text = vi.fn();
|
||||
const transport: TeacherCloudTransport = {
|
||||
json: vi.fn(async url => url === '/questions' ? { request_id: requestId, run_id: 'run' }
|
||||
: ++reads === 1 ? { status: 'running', thread_id: 'main' } : { status: 'completed', output: '最终正文' }),
|
||||
events: vi.fn(async (_url, _signal, accept) => {
|
||||
const start = { stream_event: { type: 'tool_call', tool_call_id: 'call', name: 'search', args: { private: 'private-args' } } };
|
||||
const finish = { status: 'stream_event', event: { method: 'tools', data: { event: 'tool-finished', tool_call_id: 'call', output: { status: 'success', content: 'private-result' } } } };
|
||||
accept('messages', { thread_id: 'child', payload: { items: [start] } }, '1-0');
|
||||
accept('messages', { thread_id: 'main', payload: { items: [start] } }, '2-0');
|
||||
accept('custom', { thread_id: 'main', payload: { chunk: finish } }, '3-0');
|
||||
accept('messages', { thread_id: 'main', payload: { items: [start] } }, '4-0');
|
||||
}),
|
||||
};
|
||||
await prepareCloudTeacher(f.account, f.topic, requestId, f.access, f.progress, f.saveRequest, transport, activity)
|
||||
.run([{ role: 'user', content: '问题' }], new AbortController().signal, text);
|
||||
expect(activity.mock.calls).toEqual([
|
||||
[{ id: 'run:call', name: 'search', status: 'running' }],
|
||||
[{ id: 'run:call', name: 'search', status: 'completed' }],
|
||||
]);
|
||||
expect(text.mock.calls).toEqual([['最终正文']]);
|
||||
});
|
||||
|
||||
it('submits the active discussion protocol, current tool content and selected focus', async () => {
|
||||
const f = await fixture();
|
||||
f.topic.definition.limits.max_input_tokens = 16000;
|
||||
@@ -448,6 +486,7 @@ it.each(['suggestions', 'discussion-v1'] as const)(
|
||||
const finalOutput = JSON.stringify(result);
|
||||
let firstReads = 0, resumedReads = 0;
|
||||
const text = vi.fn();
|
||||
const activity = vi.fn();
|
||||
const transport: TeacherCloudTransport = {
|
||||
json: vi.fn(async (url) => {
|
||||
if (url === '/questions') return { request_id: requestId, run_id: 'before-read' };
|
||||
@@ -481,9 +520,13 @@ it.each(['suggestions', 'discussion-v1'] as const)(
|
||||
}),
|
||||
};
|
||||
await prepareCloudTeacher(
|
||||
f.account, f.topic, requestId, f.access, f.progress, f.saveRequest, transport
|
||||
f.account, f.topic, requestId, f.access, f.progress, f.saveRequest, transport, activity
|
||||
).run([{ role: 'user', content: '一起讨论' }], new AbortController().signal, text);
|
||||
expect(text.mock.calls).toEqual([[finalOutput]]);
|
||||
expect(activity.mock.calls).toEqual([
|
||||
[{ id: 'before-read:file', name: 'read_project_file', status: 'running' }],
|
||||
[{ id: 'before-read:file', name: 'read_project_file', status: 'completed' }],
|
||||
]);
|
||||
const response = text.mock.calls.map(([delta]) => delta).join('');
|
||||
expect(format === 'suggestions'
|
||||
? parseTeacherSuggestions(response)
|
||||
|
||||
Reference in New Issue
Block a user