41366dd71d
- 移除 chatComposerDraftToDirectCodexUserItem 对纯空白 input_text 的预过滤,原样传递 draft.content - ChatComposerDraft 只保留 canonical content,删除 text / references 旧字段 - 新增 directCodexContentToPromptText、hasMeaningfulDirectCodexContent、directCodexUserItemFromContent 供 caller 与展示派生 - 删除 executeChatAgentReply 的 userItem 兜底分支,首页首轮、队列出队、普通提交与策略重试显式构造 canonical user item - QueuedChatTurn 只保存 clientTurnId 与 userItem,队列 chip 文案由 content 派生 - 旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留下迁移 TODO - 资源输入区对外只暴露 canonical content,内部文本草稿改为文本 → content 重建 - 迁移草稿、润色、队列与 appSurface 测试 fixture 到 content-only - 更新 canonical content 里程碑与实施计划文档结论
107 lines
3.2 KiB
TypeScript
107 lines
3.2 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 做主视觉');
|
|
});
|
|
});
|