fix/引用持久化 #365
Closed
k88936
wants to merge 100 commits from
fix/ref-persistent into master
pull from: fix/ref-persistent
merge into: GenarrativeAI:master
GenarrativeAI:master
GenarrativeAI:rm/design-v2
GenarrativeAI:codex/agc-project-upload-download
GenarrativeAI:feat/jenkins-mac-build
GenarrativeAI:feat/gptimage2to2.5
GenarrativeAI:feat/tribo3d-integeration
GenarrativeAI:feat/agc-organize-assetkind
GenarrativeAI:feat/mac-universal-package
GenarrativeAI:feat/ui-editor-v3
GenarrativeAI:refactor/split-direct-project
GenarrativeAI:fix/agc-acceptance-followup
GenarrativeAI:feat/agc-canvas-acceptance
GenarrativeAI:feat/more-ref
GenarrativeAI:feat/bgfilter-api
GenarrativeAI:fix/ci
GenarrativeAI:codex/platform-session-identity-credential-split
GenarrativeAI:fix/chat-state
GenarrativeAI:feat/Crt_Ws
GenarrativeAI:codex/fix-model-refresh
GenarrativeAI:feat/smart-ref-ui-res
GenarrativeAI:codex/preview-llm-router-config
GenarrativeAI:fix/stroke-width-regression-from-285
GenarrativeAI:agent-organize
GenarrativeAI:feat/expose-image2edit
GenarrativeAI:feat/game-agent-canvas-resource-workbench-v2
GenarrativeAI:feat/agc-new-workflow
GenarrativeAI:fix/agc-release-version-sync
GenarrativeAI:codex/shared-components-followup
GenarrativeAI:codex/agc-runtime-generation-reliability
GenarrativeAI:codex/game-agent-runtime-interaction-design
GenarrativeAI:feat/spine-sequence-export-v2
GenarrativeAI:codex/agc-platform-account-editor-api
GenarrativeAI:codex/game-agent-run
GenarrativeAI:codex/ui-spritesheet-durable-transaction-latest
GenarrativeAI:feat/art-agent-more-tools
GenarrativeAI:codex/editor-canvas-null-source-repair
GenarrativeAI:hotfix/editor-layout-2mib
GenarrativeAI:codex/showcase
Labels
Clear labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Breaking change that won't be backward compatible
Something is not working
Documentation changes
Improve existing functionality
New functionality
This is security issue
Issue or pull request related to testing
Priority
Critical
1
The priority is critical
Priority
High
2
The priority is high
Priority
Low
4
The priority is low
Priority
Medium
3
The priority is medium
Reviewed
Confirmed
1
Issue has been confirmed
Reviewed
Duplicate
2
This issue or pull request already exists
Reviewed
Invalid
3
Invalid issue
Reviewed
Won't Fix
3
This issue won't be fixed
Status
Abandoned
3
Somebody has started to work on this but abandoned work
Status
Blocked
1
Something is blocking this issue or pull request
Status
Need More Info
2
Feedback is required to reproduce issue or to continue work
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
陶泥儿gameAgent
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: GenarrativeAI/Genarrative#365
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "fix/ref-persistent"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
close #360
after:

1.
apps/ai-game-creator-shell/src/App.tsx:6490的directTurnInput.userItem重复赋值userItem: effectiveUserItem,后面又再次赋同一值。2c623bb57(移除 DirectProject 回合输入的重复赋值)。2.
apps/ai-game-creator-shell/src/App.tsx:6070非 DirectCodex 路径提前创建回合身份handleChatSubmit无条件创建 DirectCodex 回合 ID 和 user item,随后旧 Supervisor/策划路径也会接收到该可选 ID。b3b5d7799(按运行模式创建 DirectProject 回合输入)。3.
direct_project_history.rs:185-190删除 legacy 行投影导致历史读取失败response_item行失败关闭。4.
codex_app_server/mod.rs:15-16顶层sha2import 未使用Sha256/Digest计算输出、认证和配置摘要。5.
ResourceReferenceInput.tsxsameDraft比较 content 造成反复回写EditorState单一 authority;文本、引用和 canonicalcontent[]都从该 state 读出。sameDraftValue/sameCanonicalDraft是旧双状态同步的补偿,会造成重复比较和潜在回写。OnChangePlugin产生。6.
ResourceReferenceInput.tsx:205-210资源引用到 content part 的映射重复chatReferenceToContentPart。提交:f213987f9(复用资源引用的统一内容映射)。7.
resourceReferences.tscontent 缺失时把 text/references 拼成猜测输入EditorState派生的 canonicalcontent[];转换入口不再读取text + references猜测顺序。input_text构造。8.
resourceReferences.ts:130-132嵌套三元表达式if/else三分支。提交:a543b75cf(拆开聊天草稿内容分支判断)。10.
wire.rs:43-44校验与 wire 投影重复读取 manifestf2030a616(复用 DirectProject 用户输入校验读取的 manifest)。11.
model.rs:67-69未使用的DirectCodexUserMessageEnvelopecd2edd696(移除未使用的 DirectProject 输入信封类型)。12.
direct_runtime/user_input.rs附件未进入 DirectProject 模型 promptDirectCodexTurnAttachmentsidecar;canonical user item 不新增附件 part。render_direct_codex_user_prompt;图片、Markdown 和其它文件统一输出原名、项目路径、类型、大小、状态。附件-only 输入允许在 sidecar 渲染前保持空 canonical 文本。13.
direct_runtime/mod.rs:4169两个互斥分支克隆整个 optional JSONdirect_user_item调用.clone()。22e830ff9(避免 DirectProject 回合输入的无必要克隆)。14.
ResourceReferenceInput.tsx:192-194空白 text node 进入 canonical contentinput_text,Rust 校验拒绝 trim 后为空的 part。3c7b02b9f(过滤 DirectProject 编辑器的空白内容 part)。15.
direct_project_history_wire.rs:18-21标准历史 item 被重新投影为错误 wire 形状direct_codex_user_item_to_response_item后,文本 part 当前明确生成为type: "input_text"。response_item_projection_uses_input_text_not_turn_input_text测试已覆盖该口径,不需要迁移或 fallback。16.
codex_app_server/mod.rs:2661-2663canonical AGC part 写入聊天历史后读取丢失textcontent part。17.
App.tsx:6072chatContent 可能携带空白 input_textchatComposerDraftToDirectCodexUserItem转换入口过滤纯空白input_text。提交:35733f0e3(过滤 canonical 草稿中的空白输入 part)。18.
App.tsx:743-745规划 V2 提交后未清理引用草稿chatReferences和chatContent。提交:c266ae7b5(清理策划模式提交后的聊天草稿)。19.
direct_codex_user_item/wire.rs:26-30response item 使用text而非input_textdirect_codex_user_item_to_wire_input内部确实使用type: "text",但它只服务 turn/start prompt;历史 response item 走另一个投影函数,并明确改成type: "input_text"。21.
direct_runtime/user_input.rs:51-62显式校验与空 prompt 分支重复/不可达direct_codex_user_item_to_prompt已包含校验和空 prompt 失败,外层再次校验并检查空字符串。1da106af7(避免重复校验 DirectProject 用户输入)。Review 复核与处理结果
以下结论以当前代码为准;
review.txt只是临时清单,不纳入任何提交。1.
apps/ai-game-creator-shell/src/App.tsx:4375-4377总控纯聊天草稿恢复后被立即清空(high)OnChangePlugin,空文本覆盖刚恢复的草稿。b60750191(修复总控草稿恢复后被清空)。2.
apps/ai-game-creator-shell/src/App.tsx:4618准备建议命令时残留旧引用(medium)replaceText()按设计保留当前编辑器中的引用节点。clear()再replaceText()。已提交30e27abc6(修复建议命令草稿残留引用)。3.
apps/ai-game-creator-shell/src/view/project-development/index.tsx:8127-8130快速编辑润色结果未进入编辑器(medium)initialDraft;润色回调只更新 panel 状态。ResourceReferenceInputHandle,润色时幂等回写编辑器文本。已提交d5c4e0e78、fc0fd846f。4.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:1010-1012润色按钮不会随输入启用(high)OnChangePlugin中变更的 ref。draftTextstate,编辑器变更时同步,按钮改读 state。已提交0b9d16e8f(修复润色按钮无法感知输入)。5.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:644-645空初始草稿吞掉首次编辑(medium)645d806fe(修复空初始草稿吞掉首次编辑)。6.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:867-868清空草稿后润色状态残留(medium)OnChangePlugin同步重置润色结果和确认标记。已提交64a52005f(修复清空草稿后润色状态残留)。7.
apps/ai-game-creator-shell/src/App.tsx:3083-3084初始化阶段空持久化覆盖总控草稿(high)fa99d9ad6(避免总控草稿初始化误删)。8.
apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts:121-123canonicalcontent为空时丢失文本/引用(high)chatComposerDraftToDirectCodexUserItem(draft, id):把输入框的ChatComposerDraft转成 Rust/Direct Codex 接收的DirectCodexUserItem,其中content是唯一 canonical 消息内容。input_text(引用后的分隔空格、段落换行)在转换函数里又过滤了一遍。这个过滤其实已经由 Lexical 投影层做过(Rustvalidate_direct_codex_user_item会拒绝空input_text),属于重复过滤,只会让人误以为“转换函数在替用户改写内容”。App.tsx的userItem ?? chatComposerDraftToDirectCodexUserItem(...):??左边没传userItem时才执行右边的兜底构造,而兜底传的是{ text: prompt, references, content: [] }。首页首轮创建也走这条兜底。此时prompt/references有值、content却是空数组,最终 user message 的文本与引用被静默丢掉。draft.content,不再做二次过滤;ChatComposerDraft删掉text/references,只保留content;删除executeChatAgentReply的userItem兜底分支,首页首轮、普通聊天提交、运行中队列出队、策略确认重试全部显式构造 canonical user item;发送前只在最终 content 上判断是否全空(hasMeaningfulDirectCodexContent),不做预过滤;旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留迁移 TODO。已提交41366dd71。directCodexUserItemFromContent(content, id);需要文本的地方(草稿持久化、队列 chip、润色判据)用directCodexContentToPromptText(content, assets)从 content 派生,不要再引入并行的文本字段。9.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:641-643快速编辑initialDraft单次应用导致润色后显示旧文本(high,和第 3 条重复)d5c4e0e78、fc0fd846f。ResourceReferenceInput.tsx引用后换行被丢 → 已修,提交280a2dc5dchatComposerQueue.ts队列 chip 露出内部 resourceId → 已修,提交869abad87project-development/index.tsx快速编辑比较口径漏manifest.assets→ 已修,提交e46983154project-development/index.tsx快速编辑出站 prompt 漏manifest.assets→ 已修,提交e46983154(第 3、4 条同一根因、必须同一次提交:只改比较或只改落盘,都会让
replaceText每次输入重跑一遍)附带:仓库里原本就是红的
tests/projectResourceLiveIntegration.test.tsx > 快速编辑提示词里能 @ 出资源选择器随第 3、4 条一起转绿(期望
把夜色改成星空@rules,此前实际把夜色改成星空@source-rules)。ResourceReferenceInput的DraftContentCollector)只会把待写文本「向前合并」到下一个文本 part 上。所以@素材+ 换行 + 文字 =[reference, {text:'\n文字'}](已修),但@素材+ 换行 + 后面没有文字、或@素材+ 换行 +@另一个素材时,这段纯空白无处可挂,仍然被丢掉,读出来是@素材/@素材@另一个素材。validate_direct_codex_user_item明确拒绝text.trim().is_empty()的input_text(错误信息「DirectProject input_text 不能为空」)。因此只要前一个 part 不是文本、后面又跟的是引用,分隔符在契约层就没有合法落点。input_text,前端照原样投影(最贴近编辑器真相,但放宽了 canonical 输入白名单);② 新增显式分隔 part(例如input_text之外的separator),wire 投影时再翻译成\n(契约变更 + 历史重放要一起考虑);③ 接受现状,把「引用后必须跟文字才有换行」写进文档当作既定语义。if (text.trim() || text.includes('\n')) content.push({type:'input_text', text})不能直接用——它会把@素材\n@素材变成[ref, {text:'\n'}, ref],被上面那条 Rust 校验拒绝,整轮消息发不出去(用户看到「DirectProject input_text 不能为空」)。Agent 采用的是「向前合并」口径,请你确认这个口径就是你要的。queuedChatTurnLabel的assets默认值是否要收掉queuedChatTurnLabel(turn, assets = []),不传时退回@resourceId(保留旧调用方与既有单测的可编译性)。唯一的产品调用点(ComposerTurnQueue)已由ProjectSupervisorView传入chatProjectAssets。assets改成必填(assets: readonly GameCreationAppAssetManifestEntry[]),并把tests/appSurface/chat-composer.suite.ts里那条「不传清单退回稳定 id」的断言删掉。属于 API 口径收紧,会影响该 helper 的其它调用方(目前只有测试),要不要做由你定。initialContent仍然只用quickEditPanel.prompt文本回填key={quickEditSourceLayer?.id})时把prompt作为单个input_textpart 塞进输入区,引用 chip 靠buildDraftSegments用@显示名token 反查重建。@显示名token 且 manifest 里能找到同名素材」时 chip 才能复原;如果提示词里的 token 被用户删掉/改名,chip 就退化成普通文字。第 3、4 条修好之后,出站 prompt 的显示名口径已经统一,但「面板重开 → chip 复原」这条链路仍依赖 token 文本匹配。ChatReference[])随quickEditPanel一起保存,重开面板时直接回填 content 而不是重建。这会改面板状态结构(QuickEditPanelState)与其持久化/恢复口径,属于跨模块改动,建议单独立里程碑再做。- 新增 direct_thread_wire.rs:DirectThreadItem / DirectThreadEvent / 订阅与历史切片全部改成 ts-rs 导出的 tagged enum,取代原大而全的可空结构体 - 删除 direct_thread_raw_item.rs,模块注册与直通引用改到 direct_thread_wire - 条目身份只看一个 itemId:工具条目的第二个 id 在 Rust 边界归一,不再对外暴露 - 删除 DirectProject 聊天事件里的 turn id:生命周期用无载荷的 turn.started / turn.completed{status} 表示 - append 直接接收 DirectThreadEvent 并返回同一事件,队列内部自算 seq - 请求事件改为携带 DirectThreadRequestKind,去掉字符串中转 - 思考增量走 ReasoningDelta 通道,与正文增量共用 item.delta - at 用 #[ts(as = "f64")] 对齐 Tauri JSON 通道的 number - 用 cargo test export_bindings 重新生成 project-workspace/generated 绑定- direct_codex_notification_event 收编 resolution / request / item / rawItem / Terminal 全部分支,并接收 turnId - 读取器删掉自己那份内联分类,只保留「必须有 turnId 才处理」与活动/正文节流 - agentMessage 缺 itemId 的告警与 direct-missing-item:{turnId} 兜底身份原样保留,避免行为变化 - 新增 direct_notification_classification_covers_the_reader_branches 钉住各分支;E2E 假 app-server 用例继续覆盖读取器Review 复核结果
以下结论基于当前工作区代码重新核对。
✅表示已自动修复并单独提交;⏸表示问题仍成立,但涉及输入/提示词/审计/UI 契约或可能改变现有行为,按要求留给你;⚪表示不是可直接修复的代码问题。✅ 1.
apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs:103-120(安全,中):当前 wire 摘要会先复用附件清洗函数,再输出给模型;名称会去控制字符并提取 basename,媒体类型会去控制字符并按允许格式清洗,本地路径也会归一化为项目相对路径,避免换行、绝对路径或反斜杠破坏摘要结构。已补充清洗后的摘要测试;提交70fa16081。✅ 2.
apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:41-50(安全,中):资源引用、运行区域引用和 inline 附件现在分别计数;inline 附件使用独立的MAX_DIRECT_CODEX_ATTACHMENTS上限(8),不能再通过agc_attachment_reference绕过引用数量门禁放大 prompt。已补充超限拒绝测试;提交50204ff7a。✅ 3.
apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:54-67(缺陷,中):校验现在要求status=imported必须提供非空、有效的项目相对路径;failed可以没有路径,但如果带路径仍必须通过路径校验。这样不会再把“已导入但无项目路径”或未归一化路径交给后续 wire 投影;已补充对应测试。提交bc1dc868a。✅ 4.
apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/user_input.rs:45(重复记录):DirectProject 已经把完整回合写入.agent/conversations/project.jsonl,额外创建DirectCodexTurnAudit只会再写一份.agent/runtime/direct-codex/turns/*.jsonl,而且原调用还传了空附件列表。已移除 DirectProject 入口的审计器创建、结束和传递,提交faed0ec25;底层可选参数与独立审计测试保留。✅ 5.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:204-438(缺陷,中):referenceFromContentPart原本没有处理agc_attachment_reference,applyContentToRoot会静默丢弃初始草稿附件。已新增 LexicalAttachmentReferenceNode与可移除 chip,初始化时插入附件节点,读回时重新生成完整agc_attachment_referencepart,并注册到编辑器节点列表;提交d8af0fa88。✅ 6.
apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts:51-166(兼容残留):当前生产调用均已提供content,没有实际的“旧调用者”需要这条 fallback。已将ChatComposerDraft.content设为必填 canonical 唯一来源,删除text + references重建分支,并移除调用方无效的?? []兜底;提交840baf208。✅ 7.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:239-241(可维护性,低):资源与运行区域两条三元分支都返回同一个@${reference.label},条件没有行为意义。已改为直接使用统一表达式,提交06004bfee(清理资源引用标签的重复分支)。✅ 8.
apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:724-749(缺陷,中):初始草稿 effect 现在会在包含资源引用且assetsById为空时先返回,不提前设置 applied guard;manifest 到达后 effect 会重试并恢复资源引用。提交6e63a118e,并留下 TODO:未来可以让 Lexical 资源节点自己通过 manifest/context 解析资产名称。✅ 9.
apps/ai-game-creator-shell/src/App.tsx:12306(缺陷,低):历史命令原先改用含附件派生的canonicalPrompt判断,待发送附件会把/history变成/history@文件名,导致命令被当作普通消息发送。已改为使用不含附件的文本输入prompt判断,提交b73a329b2(修复附件场景下历史命令识别)。⚪ 10.
apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs:103-109(原报告表述过度):PROJECT_ATTACHMENT_HEADER是旧的render_direct_codex_user_prompt(prompt, attachments)文本提示,目前该函数只被首页回合调用;当前项目 DirectProject 走 inlineuser_itemwire 投影,并没有证据证明这里发生了“旧项目 header 被移除”的回归。inline 摘要确实没有这句额外指引,但是否补上属于提示词一致性选择,不应直接定为中等级缺陷。✅ 11.
apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs:41-53(可维护性,低):inline 附件现在复用附件参数路径的元数据约束:名称拒绝控制字符并限制为 160 个字符,媒体类型拒绝空值、非法字符并限制为 96 个字符;清洗上限常量也已共享,避免异常元数据进入 canonical item 和模型 prompt。已补充拒绝测试;提交75ec3361d。⚪ 12. LLM retry report summary(报告元信息):原报告中的两次请求因 core review/comment filtering 超时而失败,没有对应的源代码定位或可验证修复项。这是 review 运行失败记录,不是当前代码问题;如需结论,应在相关文件范围重新运行 review。
审查结论
要求修改。
DirectProject 提交、历史和 Rust 校验这条主路径已经收敛到 canonical
content[],附件也走 inlineagc_attachment_reference,userItem不再从text/references猜测重建。生产聊天输入区却仍把value+references回写进 Lexical,和 content-first 草稿不一致:同一素材插两次会循环重建,素材从 manifest 消失时会先拆掉结构化 chip,绕过 fail-closed。问题统计
必须先修两个缺陷。建议和 nit 不阻塞,但测试缺口和受控回写是同一根因,最好一起收。
已核对、本轮不重提
queuedChatTurnLabel的assets默认值已修。input_text;chip 之间没有后续文字时换行仍可能丢掉,按作者说明暂不作为本轮阻塞项。@显示名token 重建 chip:作者已声明后续里程碑,本轮不阻塞。@@ -31,10 +31,9 @@ pub(crate) fn normalize_direct_client_turn_id(pub(crate) async fn chat_with_game_creator_direct_codex(project_path: String,prompt: String,[nit]
prompt参数现在完全没用,真正进模型的是direct_codex_user_item_to_prompt(&user_item)。前端仍会传带@显示名的prompt,后人很容易再把它接回 Codex。建议: 改成
_prompt保留 IPC 字段,或在前端停止发送的同一次变更里删掉。不要重新使用客户端prompt。@@ -4078,0 +4087,4 @@);return asset? [resourceReferenceFromAsset(asset, 'asset-picker')]: [];[缺陷] 素材在
manifest.assets里找不到时这里返回[]。受控 effect 看到更短的desiredRefs,就会applyDraftToRoot(desiredValue, desiredRefs),把还在编辑器里的结构化 chip 拆掉。用户最后只剩普通@resourceId文本;Rust 本应 fail-closed「引用的素材已不存在,请移除后重新选择」,但这条路径在提交前就把引用弄没了。画布删掉 composer 里还挂着的素材,或 lookup 暂时为空时都会触发。建议: 提交前不要把未解析的
resourceId从编辑器里删掉。让 Rust 校验拒绝这一轮;若 UI 要提前警告,把 chip 标成失效,而不是删除 part。@@ -633,2 +739,4 @@if (initialDraftAppliedRef.current || !initialContent) {return;}// Manifest assets can arrive after the initial editor mount. Do not mark the[建议] 这几处英文注释在复述改动或设计历史(manifest 晚到、Lexical 自己解析 label 的 TODO、
The pure projection is exported…、AttachmentReferenceNode的英文 class 注释)。中文主模块里不要堆实现过程。建议: 删掉叙事/TODO。只有「
assetsById为空时先不要把 initial draft 标成已应用」这条不变量需要一行中文说明。@@ -642,0 +780,4 @@`${reference.type}:${reference.type === 'resource' ? reference.resourceId : reference.label}`,).join('|');if (current.text === desiredValue && currentRefKey === desiredRefKey)[缺陷] 生产聊天仍把
value/references回写进 Lexical。readResourceReferenceDraft会走dedupeChatReferences,handleChatComposerChange不会。同一素材两个 chip 时,currentRefKey是resource:hero,desiredRefKey是resource:hero|resource:hero,每次onChange都会applyDraftToRoot+$getRoot().selectEnd()。这是更新循环:光标被拽到末尾,React 可能打到 maximum update depth。applyDraftToRoot也不能 round-tripagc_attachment_reference,重建时会丢掉 inline 附件。同一素材插两次是编辑器支持的操作。建议: 清空/恢复/建议命令走
composerRef.clear()/applyContentToRoot/replaceText,比较用 canonicalcontent[](或能保留重复 part 的指纹)。如果受控 props 还要留一阵,父级和编辑器必须用同一套引用身份,且相等判断必须基于 content;applyDraftToRoot(text, refs)不是collectDraftParts的无损逆运算。@@ -789,2 +831,2 @@/>,);// 切换 / 重开会话:通过输入区 handle 替换 Lexical 唯一状态。composerRef.current?.replaceText('恢复出来的草稿');[建议] 测试现在用
initialContent+getDraft()/replaceText,但生产 Direct Codex 聊天不是这条路:它仍用value+references控制编辑器,提交读的是 ReactchatContent,不是composerRef.getDraft()。上面两个缺陷因此没有覆盖。建议: 留一个生产形态 fixture(
value+references+onChange写回父状态,提交读父状态),覆盖同一素材插两次、以及 composer 里的素材从assets/manifest删除。断言不要额外applyDraftToRoot/ 光标跳动,结构化agc_resource_reference要活到 fail-closed 校验。必须要和supervisior路径做明确的切割, 不然这类问题没完没了了 转向 #420
supervisor马上要删除了
Pull request closed