Merge teacher composer and compact prompt UI into main
This commit is contained in:
@@ -33,6 +33,7 @@ import { TeacherConversationStore } from './conversation-store';
|
||||
import { readJsonFile } from '../coding-projects/atomic-json';
|
||||
import { compileTeacherContext } from './context';
|
||||
import { prepareTeacherModel } from './model-runner';
|
||||
import { teacherModelCatalog, validateTeacherModelId } from './model-catalog';
|
||||
import { prepareCloudTeacher } from './cloud-runner';
|
||||
import { readTeacherSource } from './source-reader';
|
||||
import { applyTeacherReply, teacherReplyInstructions } from './reply';
|
||||
@@ -60,6 +61,7 @@ export interface TeacherServiceOptions {
|
||||
prepareModel?: typeof prepareTeacherModel;
|
||||
prepareCloud?: typeof prepareCloudTeacher;
|
||||
catalog?: typeof teacherCatalog;
|
||||
models?: typeof teacherModelCatalog;
|
||||
readSource?(scope: TeacherScope): Promise<TeacherSourceContext>;
|
||||
}
|
||||
export class CodingTeacherService {
|
||||
@@ -101,6 +103,9 @@ export class CodingTeacherService {
|
||||
: null;
|
||||
return { ...status, definition: published?.payload ?? null };
|
||||
}
|
||||
async models(runtime: 'local' | 'yuxi') {
|
||||
return (this.options.models ?? teacherModelCatalog)(await this.account(), runtime);
|
||||
}
|
||||
async catalog() {
|
||||
return (this.options.catalog ?? teacherCatalog)(await this.account());
|
||||
}
|
||||
@@ -421,6 +426,7 @@ export class CodingTeacherService {
|
||||
checkIn?: { source: TeacherSourceContext; fingerprint: string }
|
||||
): Promise<TeacherTopic> {
|
||||
teacherTopicId(input.requestId);
|
||||
const modelId = validateTeacherModelId(input.modelId);
|
||||
const intent = input.intent === undefined ? 'question' : input.intent;
|
||||
const structuredReply = intent !== 'check-in';
|
||||
if (!['question', 'suggestions', 'guided-help', 'check-in'].includes(intent) || (intent === 'check-in' && !checkIn))
|
||||
@@ -458,6 +464,7 @@ export class CodingTeacherService {
|
||||
if (existing) {
|
||||
if (
|
||||
existing.text !== input.text ||
|
||||
existing.modelId !== modelId ||
|
||||
(scope.agentId && existing.projectId !== scope.projectId) ||
|
||||
(existing.intent ?? 'question') !== intent ||
|
||||
JSON.stringify(existing.references) !== JSON.stringify(refs) ||
|
||||
@@ -485,6 +492,7 @@ export class CodingTeacherService {
|
||||
const previous = topic.requests.at(-1);
|
||||
const reuse = previous && !previous.origin && previous.projectId === scope.projectId
|
||||
&& previous.sourceConversationId === input.sourceConversationId
|
||||
&& previous.modelId === modelId
|
||||
&& previous.presentation === 'reply-v1'
|
||||
&& previous.teacherVersion === selected.version && previous.runtimeThreadId;
|
||||
newConversationSegment = !reuse;
|
||||
@@ -551,6 +559,15 @@ export class CodingTeacherService {
|
||||
return structuredClone(ref);
|
||||
});
|
||||
const isCloud = topic.definition.runtime === 'yuxi';
|
||||
if (modelId) {
|
||||
const models = await (this.options.models ?? teacherModelCatalog)(account, isCloud ? 'yuxi' : 'local');
|
||||
if (!models.supported || !models.models.some(item => item.id === modelId))
|
||||
throw new TeacherError(422, 'teacher_model_unavailable', models.message ?? '这个模型暂不可用,请重新选择。');
|
||||
this.assertAccount(account);
|
||||
}
|
||||
const modelDefinition = modelId
|
||||
? { ...topic.definition, model: { model_id: modelId, reasoning_choice: { mode: 'default' as const } } }
|
||||
: topic.definition;
|
||||
if (!isCloud && !topic.definition.system_prompt.trim())
|
||||
throw new TeacherError(422, 'teacher_definition_invalid', '请先配置智能体的系统提示词。');
|
||||
const access = scope.projectId === 'preview' ? undefined : {
|
||||
@@ -579,7 +596,7 @@ export class CodingTeacherService {
|
||||
topic.revision++;
|
||||
this.events.emit(key, structuredClone(topic));
|
||||
})
|
||||
: await (this.options.prepareModel ?? prepareTeacherModel)(account, topic.definition,
|
||||
: await (this.options.prepareModel ?? prepareTeacherModel)(account, modelDefinition,
|
||||
access,
|
||||
{ finalOnly: structuredReply });
|
||||
if (checkIn) this.assertAccount(account);
|
||||
@@ -620,6 +637,7 @@ export class CodingTeacherService {
|
||||
text: input.text,
|
||||
references,
|
||||
createdAt: new Date().toISOString(),
|
||||
...(modelId ? { modelId } : {}),
|
||||
sourceCursor: source.cursor,
|
||||
sourceCapturedAt: source.capturedAt,
|
||||
includedSourceMessageIds: compiled.includedSourceMessageIds,
|
||||
@@ -677,7 +695,8 @@ export class CodingTeacherService {
|
||||
current.response = '';
|
||||
delete current.suggestedQuestions;
|
||||
}
|
||||
topic.updatedAt = new Date().toISOString();
|
||||
current.finishedAt = new Date().toISOString();
|
||||
topic.updatedAt = current.finishedAt;
|
||||
topic.revision++;
|
||||
try {
|
||||
await store.save(topic, current.id);
|
||||
|
||||
Reference in New Issue
Block a user