feat(ai): page-custom Ask AI starter questions - #14
Merged
Conversation
…at callout border - Ask AI 'Used N sources' rows showed a spine-less book glyph that read as an empty box; replace with a document/page icon (folded corner + text lines). - Drop the '01 / 02' index prefix from sidebar section headings (and the dead .n CSS) — titles read cleaner without it. - Callouts: remove the 2px left accent stripe so the card has a uniform hairline border + background tint (docs + API reference).
The empty-state suggestion chips were one generic set for every page. Make
them page-aware with a three-layer resolution (no runtime AI cost, never
embarrassing on arbitrary docs):
1. Frontmatter — authors set `aiSuggestions: [...]` per page (max 3).
Parsed in lib/docs.ts, threaded DocsShell → DocsSidebar → AskDock.
2. Build-time generation (opt-in: `ai.suggestions: true` + MARKLINE_AI_KEY) —
scripts/build-search.mjs asks the operator's model for 3 short questions
per page and writes public/ai-suggestions.json (gitignored, like llms.txt).
Pages are cached by content hash, so rebuilds only re-call the provider for
changed pages; per-page retry; failures keep the stale entry. max_tokens is
generous because reasoning models (deepseek-flash) burn tokens on hidden
reasoning before any visible content — a small cap returns empty answers.
The dock fetches the JSON once per session and looks up the current path.
3. Fallback — the existing generic trio; also used on pages with no entry.
The API reference passes surface-aware defaults (auth / 'use the {resource}
API' / error shape) — resource tags are controlled OpenAPI names, safe to
template. Heading-template generation was rejected: arbitrary docs headings
(imperatives, fragments, code, non-English) produce visibly broken grammar.
Verified against the rune docs copy: 73/73 pages generated (58 new + 15
cached, 0 failed), second run fully cached in 0.5s; frontmatter questions
render only on their page; production build green (78 pages).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #11 (which now also contains the merged #13 retrieval work). Merge #11 first; this then lands cleanly.
Also includes a small UI-polish commit (document icon for sources rows, unnumbered sidebar groups, flat callout border) from the same review session.
Problem
The Ask AI empty-state chips were one generic set on every page ("Summarize this page", …). Heading-template generation was rejected — arbitrary docs headings (imperatives, fragments, code-ish, non-English) produce visibly broken grammar on docs we don't control.
Three-layer resolution (first hit wins)
aiSuggestions: [...]page frontmatterpublic/ai-suggestions.json— generated at build time on the operator's keyai.suggestions: true+MARKLINE_AI_KEYLayer 2:
build-search.mjsasks the configured model for 3 short questions per page (same language as the page) and writes a static JSON keyed by pathname (gitignored, likellms.txt). Content-hash cache → rebuilds only re-call the provider for changed pages; per-page retry; failures keep the stale entry. Zero runtime AI cost, no rate-limit burn, works on pure-static hosting. The dock fetches the JSON once per session.The API reference passes surface-aware defaults (auth / "How do I use the {resource} API?" / error shape) — OpenAPI tags are controlled names, safe to template.
Gotcha worth knowing
First run failed 58/73 pages: reasoning models (deepseek-flash) burn
max_tokenson hidden reasoning and returnfinish_reason=lengthwith empty content at small caps. Fixed with a generous cap (1500) + retry → 73/73 generated, 0 failed; second run fully cached in 0.5 s.Verified (rune docs copy, real OpenRouter key)
tsc/lint clean; production build green (78 pages)