Add contextual teacher help entry and simplify consultation panel

This commit is contained in:
鲨鱼辣椒
2026-09-22 16:55:07 +08:00
parent 68e676cb62
commit 12d800ec51
11 changed files with 603 additions and 50 deletions

View File

@@ -26,6 +26,7 @@ import { compileTeacherContext } from './context';
import { prepareTeacherModel } from './model-runner';
import { consultationDefinition } from './consultation-role';
import { readTeacherSource } from './source-reader';
import { parseTeacherSuggestions } from './suggestions';
import { subscribeWorksSquareSession } from '../services/works-square-session';
export interface TeacherScope {
@@ -203,6 +204,13 @@ export class CodingTeacherService {
}
async send(scope: TeacherScope, id: string, input: TeacherSend): Promise<TeacherTopic> {
teacherTopicId(input.requestId);
const intent = input.intent === undefined ? 'question' : input.intent;
if (!['question', 'suggestions', 'guided-help'].includes(intent))
throw new TeacherError(422, 'teacher_intent_invalid', '提问方式无效,请重新打开老师后再试。');
if (intent !== 'question' && (
scope.projectId === 'preview' || scope.sourceId !== 'project' || (scope.role ?? 'teacher') !== 'teacher'
))
throw new TeacherError(422, 'teacher_intent_invalid', '这种提问方式只适用于项目里的老师。');
if (input.sourceConversationId !== undefined) teacherTopicId(input.sourceConversationId);
if (typeof input.text !== 'string' || !input.text.trim() || input.text.length > 6000)
throw new TeacherError(422, 'teacher_question_invalid', '请输入 1–6000 字的问题。');
@@ -228,6 +236,7 @@ export class CodingTeacherService {
if (existing) {
if (
existing.text !== input.text ||
(existing.intent ?? 'question') !== intent ||
JSON.stringify(existing.references) !== JSON.stringify(refs) ||
(existing.sourceConversationId ?? undefined) !== (input.sourceConversationId ?? undefined)
)
@@ -301,7 +310,8 @@ export class CodingTeacherService {
topic.requests,
input.text,
references,
model.inputLimit
model.inputLimit,
intent
);
// Reading context and resolving model credentials can yield while a source
// is being deleted. Project consultations must recheck the actual source.
@@ -309,6 +319,7 @@ export class CodingTeacherService {
throw new TeacherError(404, 'teacher_source_not_found', '来源会话已删除。');
const request = {
id: input.requestId,
intent,
...(input.sourceConversationId ? { sourceConversationId: input.sourceConversationId } : {}),
text: input.text,
references,
@@ -349,6 +360,12 @@ export class CodingTeacherService {
topic.revision++;
this.events.emit(key, structuredClone(topic));
});
this.assertAccount(account);
if (!controller.signal.aborted && intent === 'suggestions') {
const suggestions = parseTeacherSuggestions(current.response);
current.response = suggestions.intro;
current.suggestedQuestions = suggestions.questions;
}
current.status = controller.signal.aborted ? 'cancelled' : 'completed';
} catch (error) {
current.status = controller.signal.aborted ? 'cancelled' : 'failed';
@@ -358,6 +375,10 @@ export class CodingTeacherService {
? error.message
: '老师回复失败,已保留本次问题与收到的内容。';
} finally {
if (intent === 'suggestions' && current.status !== 'completed') {
current.response = '';
delete current.suggestedQuestions;
}
topic.updatedAt = new Date().toISOString();
topic.revision++;
try {