139 lines
6.4 KiB
TypeScript
139 lines
6.4 KiB
TypeScript
import { describe, expect, test } from 'vitest';
|
|
|
|
import { buildPrompt, PROMPT_IDS } from '@/lib/prompts';
|
|
|
|
function buildTaskEnginePrompt() {
|
|
const prompt = buildPrompt(PROMPT_IDS.TASK_ENGINE_OUTLINES, {
|
|
requirement: 'NEV-A12 新能源车动力电池包更换前安全确认',
|
|
pdfContent: 'None',
|
|
availableImages: 'No images available',
|
|
researchContext: 'None',
|
|
teacherContext: '',
|
|
userProfile: '',
|
|
});
|
|
expect(prompt).not.toBeNull();
|
|
return `${prompt!.system}\n${prompt!.user}`;
|
|
}
|
|
|
|
describe('task-engine outlines prompt', () => {
|
|
test('adds a suitability gate and non-vocational fallback', () => {
|
|
const text = buildTaskEnginePrompt();
|
|
|
|
expect(text).toMatch(/Suitability Gate|suitability gate/i);
|
|
expect(text).toMatch(/vocational procedural task/i);
|
|
expect(text).toMatch(/operation flow/i);
|
|
expect(text).toMatch(/GO\/STOP|safe\/unsafe/i);
|
|
expect(text).toMatch(/safety boundaries|safety boundary/i);
|
|
expect(text).toMatch(/not suitable/i);
|
|
expect(text).toMatch(/fall back|fallback/i);
|
|
expect(text).toMatch(/normal MAIC-style outline/i);
|
|
expect(text).toMatch(/do not (force|use|output).*procedural-skill/i);
|
|
expect(text).toMatch(/Pythagorean theorem|Newton's second law|analyzing a poem/i);
|
|
expect(text).not.toContain('{{');
|
|
});
|
|
|
|
test('defines a mixed task-engine outline structure', () => {
|
|
const text = buildTaskEnginePrompt();
|
|
|
|
expect(text).toContain('Task Engine');
|
|
expect(text).toContain('10-14 scenes');
|
|
expect(text).toContain('at least 10');
|
|
expect(text).toContain('no more than 14');
|
|
expect(text).toMatch(/mixed structure|mixed vocational/i);
|
|
expect(text).toMatch(/5-7 .*procedural-skill|5-7 .*checklist/i);
|
|
expect(text).toMatch(/2-4 .*explanation|2-4 .*slide/i);
|
|
expect(text).toMatch(/2-4 .*challenge|2-4 .*game/i);
|
|
expect(text).toContain('procedural-skill');
|
|
expect(text).toContain('slide');
|
|
expect(text).toContain('game');
|
|
expect(text).toContain('interactive');
|
|
expect(text).toContain('procedureType');
|
|
expect(text).toContain('task');
|
|
expect(text).toContain('tools');
|
|
expect(text).toContain('steps');
|
|
expect(text).toContain('successCriteria');
|
|
expect(text).toContain('errorConsequences');
|
|
});
|
|
|
|
test('asks procedural-skill scenes to vary visual framing without new fields', () => {
|
|
const text = buildTaskEnginePrompt();
|
|
|
|
expect(text).toMatch(/training mechanism[\s\S]{0,80}not a fixed UI style/i);
|
|
expect(text).toMatch(/dark checklist|dark dashboard/i);
|
|
expect(text).toMatch(/training format|visual framing/i);
|
|
expect(text).toMatch(/title[\s\S]{0,80}description[\s\S]{0,80}keyPoints/i);
|
|
expect(text).toMatch(
|
|
/light step-card board|work-order desk|safety check station|process kanban|measurement station|control-console style|GO\/STOP decision station/i,
|
|
);
|
|
expect(text).toMatch(/Do not add new schema fields|without adding new JSON fields/i);
|
|
expect(text).toMatch(/first scene must be a `?slide`?/i);
|
|
expect(text).toMatch(/10-14 scenes/i);
|
|
expect(text).toMatch(/mixed structure|mixed vocational/i);
|
|
expect(text).not.toContain('{{');
|
|
});
|
|
|
|
test('directs the first scene to start with practice rather than a concept slide', () => {
|
|
const text = buildTaskEnginePrompt();
|
|
|
|
expect(text).toMatch(/first scene must be a `?slide`?/i);
|
|
expect(text).toMatch(/course briefing|task overview/i);
|
|
expect(text).toMatch(/task purpose|vocational task purpose/i);
|
|
expect(text).toMatch(/training objectives|what will be trained/i);
|
|
expect(text).toMatch(/key training steps|operation stages/i);
|
|
expect(text).toMatch(/safety boundary|risk reminder/i);
|
|
expect(text).toMatch(/completion criteria|GO-STOP standard/i);
|
|
expect(text).toMatch(/must not be .*checklist|not be a checklist/i);
|
|
expect(text).toMatch(/generic subject introduction|pure theory lecture/i);
|
|
expect(text).toMatch(/do not create .*concept.*slide|not be a generic concept introduction/i);
|
|
expect(text).toMatch(/hands-on|procedural|operation|vocational/i);
|
|
expect(text).toMatch(/pure theory|ordinary concept/i);
|
|
expect(text).toMatch(/not all procedural-skill|Do not make every scene a procedural-skill/i);
|
|
expect(text).not.toContain('{{');
|
|
});
|
|
|
|
test('hardens the first briefing slide against dense or unstable layouts', () => {
|
|
const text = buildTaskEnginePrompt();
|
|
|
|
expect(text).toMatch(/first scene must be a `?slide`?/i);
|
|
expect(text).toMatch(/course briefing|task overview/i);
|
|
expect(text).toMatch(/stable PPT-style slide/i);
|
|
expect(text).toMatch(/exactly 3 stable information cards|3 stable information cards/i);
|
|
expect(text).toMatch(/Task Purpose/i);
|
|
expect(text).toMatch(/Key Risk/i);
|
|
expect(text).toMatch(/Task Boundary/i);
|
|
expect(text).toMatch(/4-6 macro training stages/i);
|
|
expect(text).toMatch(/compact GO\/STOP completion standard/i);
|
|
expect(text).toMatch(/safety red line/i);
|
|
expect(text).toMatch(/not a floating callout|not be a floating callout/i);
|
|
expect(text).toMatch(/more than 6 training steps/i);
|
|
expect(text).toMatch(/long arrow flowcharts/i);
|
|
expect(text).toMatch(/floating callouts/i);
|
|
expect(text).toMatch(/overlapping GO\/STOP bars/i);
|
|
expect(text).toMatch(/dense dashboards|bottom-heavy dashboards/i);
|
|
expect(text).toMatch(/16:9 slide frame/i);
|
|
expect(text).toMatch(/overflow/i);
|
|
expect(text).not.toContain('{{');
|
|
});
|
|
|
|
test('requires playable payload for task-engine game scenes without hard-coding one template', () => {
|
|
const text = buildTaskEnginePrompt();
|
|
|
|
expect(text).toMatch(/playable payload/i);
|
|
expect(text).toMatch(/concrete playable objects/i);
|
|
expect(text).toMatch(/correct outcome|target state/i);
|
|
expect(text).toMatch(/wrong-choice feedback/i);
|
|
expect(text).toMatch(/success condition/i);
|
|
expect(text).toMatch(/failure consequence/i);
|
|
expect(text).toMatch(/recommended stable patterns|fallback patterns/i);
|
|
expect(text).toMatch(/sequence-ordering/i);
|
|
expect(text).toMatch(/GO\/STOP decision/i);
|
|
expect(text).toMatch(/risk-classification/i);
|
|
expect(text).toMatch(/tool-matching/i);
|
|
expect(text).toMatch(/5-8 concrete objects|5-8 concrete objects\/cases\/cards/i);
|
|
expect(text).toMatch(/Never provide fewer than 4 playable objects/i);
|
|
expect(text).toMatch(/not the only allowed patterns/i);
|
|
expect(text).not.toMatch(/only these four patterns are allowed/i);
|
|
expect(text).not.toContain('{{');
|
|
});
|
|
});
|