From a0e84763d26070462727befec766dbfacbc7984c Mon Sep 17 00:00:00 2001 From: Fini Date: Tue, 5 May 2026 01:57:50 +0800 Subject: [PATCH] fix(ai): JSONL fallback null-parent index reads active page, not legacy field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `store.addNode(null, …)` routes the insert through `_children()` → `getActivePageChildren(doc, activePageId)` — meaning the parent list is the ACTIVE PAGE's children, not `doc.children`. The previous append-index calc read `doc.children?.length` directly, which only holds the legacy single-page fallback array. On a multi-page doc the two diverge: `doc.children` may be empty or stale while the active page already has N siblings, so the computed append index doesn't correspond to the actual insertion target — landing either before existing siblings (off-by-N) or out of bounds. Use `getActivePageChildren(document, activePageId)` to read the same list `addNode` writes into. Sub-agent generation runs on whichever page the user has active, so this matches dispatch behavior exactly. The non-null parent path (`getNodeById(parentId)` then read its children length) was already correct — only the null-parent branch needed fixing. --- .../web/src/services/ai/element-tools-dispatcher.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/web/src/services/ai/element-tools-dispatcher.ts b/apps/web/src/services/ai/element-tools-dispatcher.ts index 92feb6ab8..85b54412d 100644 --- a/apps/web/src/services/ai/element-tools-dispatcher.ts +++ b/apps/web/src/services/ai/element-tools-dispatcher.ts @@ -41,6 +41,7 @@ import { insertStreamingNode } from './design-canvas-ops'; // this dispatcher actually needs and is kept rigorously browser-safe // (enforced by `packages/pen-mcp/src/__tests__/batch-design-dsl-browser-safe.test.ts`). import { runBatchDesignDsl } from '@zseven-w/pen-mcp/dsl'; +import { getActivePageChildren } from '@zseven-w/pen-core'; import type { PenNode } from '@/types/pen'; /** @@ -570,7 +571,17 @@ function applyBatchDesignAsJsonl(jsonl: string, ctx: DispatchContext): DispatchR // Compute the parent's current child count for each insert and pass // it as the explicit index so roots land in their generation order. const computeAppendIndex = (): number => { - if (parentId === null) return useDocumentStore.getState().document.children?.length ?? 0; + if (parentId === null) { + // `addNode` writes into the ACTIVE PAGE's children (see + // document-store-node-actions.ts::_children → getActivePageChildren). + // Reading `document.children` directly would only return the legacy + // single-page fallback array — on a multi-page doc that's NOT + // where the inserts land, so the resulting append index would + // disagree with the live child list and either skip past existing + // siblings or land out of bounds. + const activePageId = useCanvasStore.getState().activePageId; + return getActivePageChildren(useDocumentStore.getState().document, activePageId).length; + } const parentNode = useDocumentStore.getState().getNodeById(parentId); if ( parentNode &&