fix(persona-sim): 演出脚本字段不全导致整页崩溃#253
Conversation
LLM 偶尔生成的 app beat 缺嵌套数组(如 view:'chat' 却无 chat.lines), 渲染到 .map 时整页崩(Safari 报 undefined is not an object)。 新增 normalizeScript 把 chat.lines / search.queries / notes.items / browser.tabs / compose.drafts 统一兜底成数组,parseScript 与生活记录 重播两条路径都过一遍,覆盖新生成脚本和旧损坏快照。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRNUmkjGJzft1rG8DvBdTw
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request introduces a normalizeScript helper function in apps/PersonaSim.tsx to ensure nested arrays within the simulation script's app beats are properly initialized, preventing rendering crashes when the LLM output is incomplete. The feedback highlights a critical issue where normalizeScript mutates its input in-place, which violates React's immutability principles when applied to props, and notes a potential TypeError if the input is null. It is recommended to add a null check and deep-clone the script object before modifying it.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| function normalizeScript(s: SimScript): SimScript { | ||
| if (!Array.isArray(s.beats)) return s; | ||
| for (const b of s.beats) { | ||
| const a = b?.app; | ||
| if (!a) continue; | ||
| if (a.chat && !Array.isArray(a.chat.lines)) a.chat.lines = []; | ||
| if (a.search && !Array.isArray(a.search.queries)) a.search.queries = []; | ||
| if (a.notes && !Array.isArray(a.notes.items)) a.notes.items = []; | ||
| if (a.browser && !Array.isArray(a.browser.tabs)) a.browser.tabs = []; | ||
| if (a.compose && !Array.isArray(a.compose.drafts)) a.compose.drafts = []; | ||
| } | ||
| return s; | ||
| } |
There was a problem hiding this comment.
在 normalizeScript 中,直接对传入的 s 进行修改(in-place mutation)会带来潜在的 React 渲染和状态管理问题。
当重播时,sim.script 作为 React 组件的 Prop 传入,直接修改它会违反 React 的不可变性(Immutability)原则,可能导致父组件状态被污染或组件未能正确触发重渲染。
此外,如果 s 为 null 或 undefined(例如 JSON.parse 解析失败返回 null),直接读取 s.beats 会抛出 TypeError。
建议在函数开头增加空值校验,并使用 JSON.parse(JSON.stringify(s)) 进行深拷贝,以确保不污染原始数据。
function normalizeScript(s: SimScript): SimScript {
if (!s || !Array.isArray(s.beats)) return s;
// 避免直接修改 React props/state,先进行深拷贝
const cloned = JSON.parse(JSON.stringify(s)) as SimScript;
for (const b of cloned.beats) {
const a = b?.app;
if (!a) continue;
if (a.chat && !Array.isArray(a.chat.lines)) a.chat.lines = [];
if (a.search && !Array.isArray(a.search.queries)) a.search.queries = [];
if (a.notes && !Array.isArray(a.notes.items)) a.notes.items = [];
if (a.browser && !Array.isArray(a.browser.tabs)) a.browser.tabs = [];
if (a.compose && !Array.isArray(a.compose.drafts)) a.compose.drafts = [];
}
return cloned;
}
「演出解析失败(parse)」是与渲染崩溃不同的失败:模型返回的 JSON 解析不出来。本次: - repair 增加去除 }/] 前尾随逗号(LLM 高频语法错误) - 解析失败时不再抛笼统的 'parse',改为带原因(空/语法错/疑似截断)+ 原文长度与首尾片段的报错,便于从系统调试终端复制定位真实原因 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRNUmkjGJzft1rG8DvBdTw
LLM 偶尔生成的 app beat 缺嵌套数组(如 view:'chat' 却无 chat.lines), 渲染到 .map 时整页崩(Safari 报 undefined is not an object)。 新增 normalizeScript 把 chat.lines / search.queries / notes.items / browser.tabs / compose.drafts 统一兜底成数组,parseScript 与生活记录 重播两条路径都过一遍,覆盖新生成脚本和旧损坏快照。
Claude-Session: https://claude.ai/code/session_01CRNUmkjGJzft1rG8DvBdTw