Files
Genarrative/apps/ai-game-creator-shell/tests/resourceReferences.test.ts
k88936 6eed6bd13f
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m10s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m43s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m28s
Project CI / Backend tests (pull_request) Failing after 15s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m13s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m0s
Project CI / Repository checks (pull_request) Failing after 12s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m58s
Project CI / Frontend tests (pull_request) Failing after 4m24s
Project CI / AI game creator shell web tests (pull_request) Failing after 4m2s
Project CI / Native shell tests (pull_request) Successful in 8m31s
收敛 content→可读文本为单一口径并强制传 manifest(review 第 2、3 条)
- directCodexContentToPromptText 的 assets 改为必填,去掉 = [] 默认值:漏传素材清单从运行期文案退化变回编译期错误
- queuedChatTurnLabel 的 assets 与 ComposerTurnQueue 的 assets 属性同样必填,队列 chip 与消息正文共用同一个派生(chip 只多做压单行与限长)
- 断言改为显式传 [] 或 manifest:resourceReferences、chat-composer 用例按新签名收敛
- 更新 pitfalls 条目与 decision-log(canonical content 有效性只判整条 content、投影逐字透传、可读文本单一口径必填 assets)
2026-09-17 14:02:21 +08:00

110 lines
3.3 KiB
TypeScript

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 做主视觉');
});
});