93 lines
4.4 KiB
TypeScript
93 lines
4.4 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import {
|
||
buildGameAssetReviewBatchMessage,
|
||
buildGameAssetReviewActionMessage,
|
||
buildGameAssetReviewMarker,
|
||
buildGameAssetConfirmationMessage,
|
||
findGameAssetRoundConfirmation,
|
||
GAME_ASSET_SELECTION_MARKER,
|
||
hasGameAssetReviewContent,
|
||
hasGameAssetSelectionMarker,
|
||
parseGameAssetReviewAction,
|
||
parseGameAssetReviewActions,
|
||
parseGameAssetReviewInvocation,
|
||
stripGameAssetSelectionMarker,
|
||
} from '@/lib/game-asset-selection-message';
|
||
|
||
describe('conversation-guided game asset selection', () => {
|
||
it('detects and hides the assistant selection marker', () => {
|
||
const message = { role: 'assistant' as const, content: `候选准备好了。\n${GAME_ASSET_SELECTION_MARKER}` };
|
||
expect(hasGameAssetSelectionMarker(message)).toBe(true);
|
||
expect(stripGameAssetSelectionMarker(String(message.content))).toBe('候选准备好了。');
|
||
});
|
||
|
||
it('round-trips an Agent-filled review marker and user action', () => {
|
||
const assistant = { role: 'assistant' as const, content: `候选准备好了。\n${buildGameAssetReviewMarker('review-1', ['hero', 'jump'])}` };
|
||
expect(hasGameAssetSelectionMarker(assistant)).toBe(true);
|
||
expect(parseGameAssetReviewInvocation(assistant)).toEqual({ invocationId: 'review-1', candidateIds: ['hero', 'jump'] });
|
||
expect(stripGameAssetSelectionMarker(String(assistant.content))).toBe('候选准备好了。');
|
||
|
||
const user = { role: 'user' as const, content: buildGameAssetReviewActionMessage({ invocationId: 'review-1', asset: { id: 'hero', name: '主角' }, action: 'approve' }) };
|
||
expect(parseGameAssetReviewAction(user)).toEqual({ invocationId: 'review-1', assetId: 'hero', action: 'approve' });
|
||
});
|
||
|
||
it('round-trips one grouped user message for the complete review batch', () => {
|
||
const message = {
|
||
role: 'user' as const,
|
||
content: buildGameAssetReviewBatchMessage({
|
||
invocationId: 'review-batch',
|
||
decisions: [
|
||
{ asset: { id: 'hero', name: '主角' }, action: 'approve' },
|
||
{ asset: { id: 'jump', name: '跳跃音效' }, action: 'discard' },
|
||
{ asset: { id: 'background', name: '背景' }, action: 'replace' },
|
||
],
|
||
}),
|
||
};
|
||
expect(message.content).toContain('游戏素材审核结果(本轮一次性提交)');
|
||
expect(message.content).toContain('纳入开发:');
|
||
expect(message.content).toContain('舍弃:');
|
||
expect(message.content).toContain('不合适,重新寻找:');
|
||
expect(parseGameAssetReviewActions(message)).toEqual({
|
||
invocationId: 'review-batch',
|
||
decisions: [
|
||
{ assetId: 'hero', action: 'approve' },
|
||
{ assetId: 'jump', action: 'discard' },
|
||
{ assetId: 'background', action: 'replace' },
|
||
],
|
||
});
|
||
});
|
||
|
||
it('detects a concrete preview list when the Agent omitted the review marker', () => {
|
||
const assistant = {
|
||
role: 'assistant' as const,
|
||
content: '已经找到 7 个素材候选。\n\n| 预览文件 | 是什么 |\n| --- | --- |\n| C-001-flappy-bird.png | 小鸟和管子 |',
|
||
};
|
||
expect(hasGameAssetReviewContent(assistant)).toBe(true);
|
||
expect(hasGameAssetReviewContent({ role: 'assistant', content: '我正在整理素材方向,暂时没有候选。' })).toBe(false);
|
||
});
|
||
|
||
it('builds a real user confirmation and associates it with the latest round', () => {
|
||
const confirmation = buildGameAssetConfirmationMessage([
|
||
{ id: 'hero', name: '主角' },
|
||
{ id: 'jump', name: '跳跃音效' },
|
||
]);
|
||
const messages = [
|
||
{ role: 'assistant' as const, content: GAME_ASSET_SELECTION_MARKER },
|
||
{ role: 'user' as const, content: confirmation },
|
||
];
|
||
expect(confirmation).toContain('「主角」(hero)、「跳跃音效」(jump)');
|
||
expect(findGameAssetRoundConfirmation(messages, 0)).toBe(messages[1]);
|
||
});
|
||
|
||
it('does not let a later round confirmation collapse an older unanswered round', () => {
|
||
const messages = [
|
||
{ role: 'assistant' as const, content: GAME_ASSET_SELECTION_MARKER },
|
||
{ role: 'user' as const, content: '换一批' },
|
||
{ role: 'assistant' as const, content: GAME_ASSET_SELECTION_MARKER },
|
||
{ role: 'user' as const, content: buildGameAssetConfirmationMessage([{ id: 'new', name: '新素材' }]) },
|
||
];
|
||
expect(findGameAssetRoundConfirmation(messages, 0)).toBeNull();
|
||
expect(findGameAssetRoundConfirmation(messages, 2)).toBe(messages[3]);
|
||
});
|
||
});
|