import { describe, expect, it } from 'vitest'; import { type ChatComposerDraft, chatComposerDraftToDirectCodexUserItem, directCodexContentToPromptText, hasMeaningfulDirectCodexContent, } from '../src/features/project-workspace/resourceReferences'; describe('DirectProject user Response item', () => { it('保留 Lexical content 的文本与引用交错顺序', () => { const draft: ChatComposerDraft = { content: [ { type: 'input_text', text: '先看 ' }, { type: 'agc_resource_reference', resourceId: 'asset-hero' }, { type: 'input_text', text: ' 再看 ' }, { type: 'agc_runtime_region_reference', label: '主画面', runId: 'run-1', versionId: 'version-1', elementTag: 'canvas', elementRole: 'playfield', text: '可试玩区域', width: 320, height: 180, resourceIds: ['asset-hero'], }, ], }; expect( chatComposerDraftToDirectCodexUserItem(draft, 'turn-1:user'), ).toEqual({ type: 'message', role: 'user', id: 'turn-1:user', content: draft.content, }); }); it('资源引用只投影稳定 resourceId,不携带展示字段', () => { const draft: ChatComposerDraft = { content: [ { type: 'input_text', text: '请使用素材' }, { type: 'agc_resource_reference', resourceId: 'asset-hero' }, ], }; expect( chatComposerDraftToDirectCodexUserItem(draft, 'turn-2:user'), ).toEqual({ type: 'message', role: 'user', id: 'turn-2:user', content: [ { type: 'input_text', text: '请使用素材' }, { type: 'agc_resource_reference', resourceId: 'asset-hero' }, ], }); }); it('原样保留纯空白 input_text,不替用户改写提示词', () => { const draft: ChatComposerDraft = { content: [ { type: 'input_text', text: '先看' }, { type: 'input_text', text: ' ' }, { type: 'agc_resource_reference', resourceId: 'asset-hero' }, { type: 'input_text', text: '\n' }, ], }; expect( chatComposerDraftToDirectCodexUserItem(draft, 'turn-3:user').content, ).toEqual(draft.content); }); it('只有最终 content 全为空白时才判定为空输入', () => { expect( hasMeaningfulDirectCodexContent([{ type: 'input_text', text: ' \n ' }]), ).toBe(false); expect(hasMeaningfulDirectCodexContent([])).toBe(false); // 空白文本仍然保留,但只要有实际文本或引用就不能当空输入拒发。 expect( hasMeaningfulDirectCodexContent([ { type: 'input_text', text: ' \n' }, { type: 'input_text', text: '看' }, ]), ).toBe(true); expect( hasMeaningfulDirectCodexContent([ { type: 'agc_resource_reference', resourceId: 'asset-hero' }, ]), ).toBe(true); }); it('展示用文本由 content 派生,引用按 @ 显示名展开', () => { expect( directCodexContentToPromptText( [ { type: 'input_text', text: '用 ' }, { type: 'agc_resource_reference', resourceId: 'asset-hero' }, { type: 'input_text', text: ' 做主视觉' }, ], [], ), ).toBe('用 @asset-hero 做主视觉'); }); });