Merge cloud-owned teaching policy and bounded new shortcuts

This commit is contained in:
鲨鱼辣椒
2026-09-28 18:06:30 +08:00
12 changed files with 319 additions and 32 deletions

View File

@@ -277,6 +277,29 @@ describe('teacher side chat', () => {
expect(api.send).not.toHaveBeenCalled();
});
it('shows the format error alongside the preserved reply while keeping excess shortcuts noninteractive', async () => {
const response = '先看看摸头会带来什么变化。';
const quickReplies = ['看懂规则|摸头会改变什么?', '想想作用|我们聊聊摸头。', '试试结果|怎样看出变化?', '换个话题|我想聊别的地方。'];
const replyParseError = '快捷回复超过当前界面最多 3 条的限制,正文已保留,快捷回复未展示。';
const raw = '\n' + JSON.stringify({ reply: response, quickReplies }, null, 2) + '\n';
api.read.mockResolvedValue({ ...first, requests: [suggestionsRequest({
presentation: 'reply-v1', response, suggestedQuestions: [], replyParseError, unparsedResponse: raw,
})] });
render(<TeacherChatPanel projectId="p" sourceId="c" />);
await ready();
expect(screen.getByText(response)).toBeVisible();
expect(screen.getByText('回答正文已保留,部分附加内容未能显示。')).toBeVisible();
for (const shortcut of quickReplies) {
expect(screen.queryByRole('button', { name: shortcut, exact: true })).not.toBeInTheDocument();
}
const details = screen.getByText('查看收到的原始内容').closest('details');
expect(details).not.toHaveAttribute('open');
expect(details?.querySelector('pre')?.textContent).toBe(raw);
expect(screen.getByLabelText('向智能体提问')).toBeEnabled();
expect(api.send).not.toHaveBeenCalled();
});
it('renders formulas and preserves code escapes while rejecting executable links and HTML', async () => {
api.read.mockResolvedValue({ ...first, requests: [request({
response: '$E=mc^2$\n\n```js\nconst value = "\\n";\n```\n\n[危险](javascript:alert)\n\n<script>alert(1)</script>\n\n![本地图片](file:///C:/secret.png)\n\n![坏图片](https://example.com/missing.png)',
@@ -771,6 +794,22 @@ describe('teacher side chat', () => {
describe('legacy discussion history compatibility', () => {
it('shows every historical shortcut even when the old reply has more than three', async () => {
const shortcuts = ['看懂规则|摸头会改变什么?', '想想作用|我们聊聊摸头。', '试试结果|怎样看出变化?', '换个话题|我想聊别的地方。'];
api.read.mockResolvedValue({ ...first, requests: [request({
presentation: 'discussion-v1', response: '这些是之前留下的讨论入口。', suggestedQuestions: shortcuts,
})] });
render(<TeacherChatPanel projectId="p" sourceId="c" />);
await ready();
expect(screen.getByText('这些是之前留下的讨论入口。')).toBeVisible();
for (const shortcut of shortcuts) {
expect(screen.getByRole('button', { name: shortcut, exact: true })).toBeEnabled();
}
expect(screen.queryByText('查看收到的原始内容')).not.toBeInTheDocument();
expect(api.send).not.toHaveBeenCalled();
});
const contents = [
{ kind: 'ideas', title: '旧想法组件', items: [{ id: 'dog', text: '养只小狗', state: 'kept' }] },
{ kind: 'structure', title: '旧结构组件', nodes: [{ id: 'dog', label: '照顾小狗' }] },