fix(ai): keep outer node array, not nested children, in parser candidate selection
Multi-candidate selection picked the candidate with the most nodes, but balanced_arrays also collected nested children arrays. For nested-format output (a single root frame whose children array holds 3 nodes), the inner array could outrank the outer (1 node), returning the children and dropping the real root. Flat _parent-style output (what M2.7 emitted in testing) hid it. balanced_arrays now collects only top-level arrays, skipping past each captured span. Adds a regression test. Found by Codex stop-time review.
This commit is contained in:
parent
b349b06f2a
commit
da21f59d20
|
|
@ -107,18 +107,25 @@ fn normalize_generated_node_json(value: &mut serde_json::Value) {
|
|||
}
|
||||
}
|
||||
|
||||
/// 收集文本里所有平衡的 `[...]` 子串(忽略字符串字面量内的方括号),
|
||||
/// 按出现顺序返回。嵌套数组的起点也会进来,但调用方按"节点数最多"
|
||||
/// 取舍,外层真实数组自然胜出。
|
||||
/// 收集文本里所有**顶层**平衡的 `[...]` 子串(忽略字符串字面量内的方
|
||||
/// 括号),按出现顺序返回。抓到一个数组后跳过其整段,**不下探嵌套的
|
||||
/// children 数组**——否则 `[{frame, children:[a,b,c]}]` 这种嵌套格式会
|
||||
/// 把内层 `[a,b,c]`(3 个)当候选,按"节点数最多"错误压过外层
|
||||
/// `[root]`(1 个)。散文里并列的括号(如 `[step 1]` 与真正的数组)互
|
||||
/// 不嵌套,仍各自作为顶层候选。
|
||||
fn balanced_arrays(text: &str) -> Vec<&str> {
|
||||
let bytes = text.as_bytes();
|
||||
let mut out = Vec::new();
|
||||
for (i, &b) in bytes.iter().enumerate() {
|
||||
if b == b'[' {
|
||||
let mut i = 0;
|
||||
while i < bytes.len() {
|
||||
if bytes[i] == b'[' {
|
||||
if let Some(end) = balanced_end(bytes, i) {
|
||||
out.push(&text[i..=end]);
|
||||
i = end + 1; // 跳过整段,不把嵌套 children 当独立候选
|
||||
continue;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
out
|
||||
}
|
||||
|
|
@ -224,4 +231,20 @@ mod tests {
|
|||
assert_eq!(nodes[0].id_str(), "a");
|
||||
assert_eq!(nodes[1].id_str(), "b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nodes_returns_outer_array_not_nested_children() {
|
||||
// 嵌套格式:外层只有 1 个 root frame,其 children 有 3 个。只收
|
||||
// 顶层数组,返回外层 [root],而不是内层 [a,b,c](Codex review)。
|
||||
let text = r#"[
|
||||
{ "type": "frame", "id": "root", "name": "Root", "x": 0, "y": 0, "width": 300, "height": 200, "children": [
|
||||
{ "type": "frame", "id": "a", "name": "A", "x": 0, "y": 0, "width": 100, "height": 50, "children": [] },
|
||||
{ "type": "frame", "id": "b", "name": "B", "x": 0, "y": 0, "width": 100, "height": 50, "children": [] },
|
||||
{ "type": "frame", "id": "c", "name": "C", "x": 0, "y": 0, "width": 100, "height": 50, "children": [] }
|
||||
] }
|
||||
]"#;
|
||||
let nodes = parse_nodes(text).expect("parse");
|
||||
assert_eq!(nodes.len(), 1);
|
||||
assert_eq!(nodes[0].id_str(), "root");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue