fix: keep teacher runtime prompts within interface boundary
This commit is contained in:
@@ -9,6 +9,13 @@ import {
|
||||
import { applyTeacherReply, teacherReplyInstructions } from '../../electron/coding-teacher/reply';
|
||||
import type { TeacherRequest } from '../../shared/coding-teacher';
|
||||
|
||||
const fourHistoricalReplies = [
|
||||
'看懂规则|摸头会改变什么?',
|
||||
'想想作用|我们聊聊摸头的作用。',
|
||||
'试试结果|怎样知道变化发生了?',
|
||||
'换个话题|我想先聊别的地方。',
|
||||
];
|
||||
|
||||
describe('teacher text and suggestions transport', () => {
|
||||
const envelope = { reply: '🍎 **先看看重力带来的变化。**', quickReplies: ['继续解释', '比较不同选择'] };
|
||||
|
||||
@@ -66,6 +73,17 @@ describe('teacher text and suggestions transport', () => {
|
||||
.toEqual({ reply: '一个入口。', quickReplies: ['继续'] });
|
||||
});
|
||||
|
||||
it('keeps four historical shortcuts intact when decoding either envelope format', () => {
|
||||
const reply = '这些是之前留下的讨论入口。';
|
||||
for (const historical of [
|
||||
{ reply, quickReplies: fourHistoricalReplies },
|
||||
{ intro: reply, questions: fourHistoricalReplies },
|
||||
]) {
|
||||
expect(parseTeacherReply(JSON.stringify(historical)))
|
||||
.toEqual({ reply, quickReplies: fourHistoricalReplies });
|
||||
}
|
||||
});
|
||||
|
||||
it('preserves long ordinary and structured replies without the old 12000 character truncation', () => {
|
||||
const reply = '🍏 云端前缀\n\n' + '这是一段完整的详细解释。'.repeat(10000);
|
||||
expect(parseTeacherReply(reply)).toEqual({ reply, quickReplies: [] });
|
||||
@@ -195,10 +213,47 @@ describe('Main reply application', () => {
|
||||
expect(current.discussionSnapshot).toEqual({ kind: 'ideas', title: '历史记录' });
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ quickReplies: [] },
|
||||
{ quickReplies: ['看懂规则|摸头会改变什么?'] },
|
||||
{ quickReplies: ['看懂规则|摸头会改变什么?', '看懂规则|摸头会改变什么?', '换个话题|我想聊别的地方。'] },
|
||||
])('applies zero to three new shortcuts without stripping prefixes or deduplicating: $quickReplies', ({ quickReplies }) => {
|
||||
const current = request();
|
||||
current.replyParseError = '之前的格式错误';
|
||||
current.unparsedResponse = '之前的原始输出';
|
||||
applyTeacherReply(current, JSON.stringify({ reply: '先看看摸头的作用。', quickReplies }));
|
||||
|
||||
expect(current.response).toBe('先看看摸头的作用。');
|
||||
expect(current.suggestedQuestions).toEqual(quickReplies);
|
||||
expect(current.replyParseError).toBeUndefined();
|
||||
expect(current.unparsedResponse).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(['current', 'legacy'] as const)('rejects four newly generated shortcuts in a %s envelope without losing the reply or raw output', format => {
|
||||
const current = request();
|
||||
current.suggestedQuestions = ['上一轮的旧选项'];
|
||||
const reply = '保留这一轮的完整正文。';
|
||||
const envelope = format === 'current'
|
||||
? { reply, quickReplies: fourHistoricalReplies }
|
||||
: { intro: reply, questions: fourHistoricalReplies };
|
||||
const raw = ' \n```json\n' + JSON.stringify(envelope, null, 2) + '\n```\n ';
|
||||
expect(parseTeacherReply(raw)).toEqual({ reply, quickReplies: fourHistoricalReplies });
|
||||
|
||||
applyTeacherReply(current, raw);
|
||||
|
||||
expect(current.response).toBe(reply);
|
||||
expect(current.suggestedQuestions).toEqual([]);
|
||||
expect(current.replyParseError).toBeTruthy();
|
||||
expect(current.unparsedResponse).toBe(raw);
|
||||
expect(current.discussionSnapshot).toEqual({ kind: 'ideas', title: '历史记录' });
|
||||
});
|
||||
|
||||
it('limits instructions to the text/suggestions shape and defers writing choices to cloud configuration', () => {
|
||||
const instructions = teacherReplyInstructions();
|
||||
expect(instructions).toContain('{"reply":string,"quickReplies":string[]}');
|
||||
expect(instructions).toContain('云端配置');
|
||||
expect(instructions).not.toMatch(/Alice|120|400|2–3|学生口吻|kind|tool|想法板|流程图/);
|
||||
expect(instructions).toMatch(/最多\s*3\s*条|0[–-]3\s*条/);
|
||||
expect(instructions).toContain('空数组');
|
||||
expect(instructions).not.toMatch(/Alice|120|400|2–3|学生口吻|kind|tool|想法板|流程图|整理想法|理解关系|承接|共识|已确认内容|待定想法/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user