Repository navigation
feat(markdown): add offline /insert-toc slash command - #423
Conversation
karaaslanz
left a comment
There was a problem hiding this comment.
Reviewed PR #423 at exact HEAD dfd69ff63972971245ad8008806c84d7c951ce19. The new asynchronous /insert-toc path can silently insert a TOC into the wrong document when the user switches tabs before the local backend responds.
Source: frontend/src/hooks/editor/useSlashCommandWiring.ts:69-79 captures text from document A, awaits Markdown.toc(text), then calls insertTableOfContents(toc) without checking that the original editor model is still current. frontend/src/hooks/editor/useEditorFormatting.ts:74-79 delegates to replaceSelection, which fetches monacoRef.current.getModel() and getSelection() at insertion time. On a tab switch, those now belong to document B. The generated TOC for A is inserted in B.
Exact-source reproduction (Node 24, no project files changed): fetched the two functions at the PR head (wiring blob 98700b2881f21cb27e5025b67a68f23338d4b9dd; formatting blob 43254c0a31640284412b1903119d20a5c7dbd584), stripped TypeScript with Node's builtin transformer, ran the original functions using deterministic mocked Monaco and a deferred Markdown.toc promise. Invoked the slash command in A (# Alpha), switched the editor ref to B (# Beta) before resolving the response, then resolved the TOC. Result: A only had the slash trigger removed; B received ## Table of Contents\n\n- [Alpha](#alpha) ahead of # Beta. Reproduced, not a speculative race. This is an isolated source-backed execution, not a full browser / end-to-end test.
Narrow fix: capture the initiating Monaco model/document identity (and preferably a version/selection/range snapshot) before the await; on completion, cancel insertion if the active model, buffer version or intended insertion location is no longer valid. The insertion helper should not blindly resolve a different model on the return path. Add a deferred-promise regression test for A?B tab switch, plus an edit/cursor-move while awaiting. Keep the feature offline/provider-free as intended.
Requesting changes for this correctness invariant only.
|
Approved. The branch has been merged with the latest main, and the offline /insert-toc feature meets the issue requirements: it generates TOCs locally through the Markdown endpoint, requires no AI provider or API key, preserves heading hierarchy and compatible anchors, and handles documents without headings gracefully. The reported async race has been fixed. The insertion target now captures the initiating Monaco editor, model, document version, and selection before awaiting the TOC response. The result is discarded if the user switches tabs, edits the document, or moves the cursor before completion, preventing content from being inserted into the wrong document or location. The AI-panel entry point is also guarded against stale document results. Regression coverage includes deferred-response tab switching, content/selection changes, and the unchanged successful path. Validation passed: 491 Python tests, 157 frontend tests, frontend lint, production build, and Ruff checks. Ready to merge. |
Closes #420.
Adds an offline /insert-toc slash command that generates a Markdown
table of contents from the document's headings, complementing the
AI-powered /toc without needing an API key or network access.
Implementation reuses the existing, already-tested offline generator
(backend.ai_logic._generate_markdown_toc) via a new lightweight
POST /api/markdown/toc endpoint, so anchors match the rendered preview
exactly. Frontend wires it through the existing slash-command path
(same as /insert-table).
Validation:
Note: the inserted TOC reuses the AI /toc output format (includes a
"## Table of Contents" header). Happy to make it list-only if preferred.