Add teacher microphone and per-question model selection

This commit is contained in:
鲨鱼辣椒
2026-09-29 19:43:45 +08:00
parent cd1ba41e21
commit 78cfde6734
20 changed files with 517 additions and 37 deletions

View File

@@ -103,6 +103,7 @@ async function fixture({ durableSource = false, sourceContext = context, liveMod
const prepareCloud = vi.fn((..._args: unknown[]) => ({ inputLimit: 8000, run }));
const createService = () => new CodingTeacherService({
projects,
models: async () => ({ supported: true, models: [{ id: 'qwen' }, { id: 'other-model' }] }),
runtime: new InMemoryConversationRuntime(),
userDataDir: root,
account: async () => account,
@@ -1659,3 +1660,22 @@ describe('project consultations with selected cloud teachers', () => {
await vi.waitFor(async () => expect((await f.service.read(scope, topic.id)).requests[0].status).toBe('completed'));
});
});
it.each([false, true])('freezes explicit model without changing teacher definition (cloud=%s)', async cloudTeacher => {
const f = await fixture({ cloudTeacher, mockCloud: cloudTeacher });
const t = await f.service.create(f.scope, undefined, undefined, cloudTeacher ? 9 : undefined);
const input = { requestId: '22222222-2222-4222-8222-222222222222', text: '帮我理解', modelId: 'other-model' };
const accepted = await f.service.send(f.scope, t.id, input);
expect(accepted.requests[0].modelId).toBe('other-model');
expect(accepted.definition.model.model_id).toBe('qwen');
if (!cloudTeacher) expect(f.prepareModel.mock.calls[0][1].model).toEqual({ model_id: 'other-model', reasoning_choice: { mode: 'default' } });
await expect(f.service.send(f.scope, t.id, { ...input, modelId: 'qwen' })).rejects.toMatchObject({ code: 'teacher_request_conflict' });
await f.service.send(f.scope, t.id, input);
expect(f.run).toHaveBeenCalledTimes(1);
f.finish();
await vi.waitFor(async () => expect((await f.service.read(f.scope, t.id)).requests[0].status).toBe('completed'));
const restarted = await f.restart();
expect((await restarted.read(f.scope, t.id)).requests[0].modelId).toBe('other-model');
await expect(restarted.send(f.scope, t.id, { ...input, requestId: '33333333-3333-4333-8333-333333333333', modelId: 'unavailable' })).rejects.toMatchObject({ code: 'teacher_model_unavailable' });
expect(f.run).toHaveBeenCalledTimes(1);
});