Skip to content

feat(ai): page-custom Ask AI starter questions - #14

Merged
oreofeolurin merged 2 commits into
mainfrom
feat/ai-page-suggestions
Jun 11, 2026
Merged

feat(ai): page-custom Ask AI starter questions#14
oreofeolurin merged 2 commits into
mainfrom
feat/ai-page-suggestions

Conversation

@oreofeolurin

Copy link
Copy Markdown
Contributor

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)

Layer Source When
1 aiSuggestions: [...] page frontmatter author-curated, always correct
2 public/ai-suggestions.json — generated at build time on the operator's key opt-in: ai.suggestions: true + MARKLINE_AI_KEY
3 the generic trio everything else

Layer 2: build-search.mjs asks the configured model for 3 short questions per page (same language as the page) and writes a static JSON keyed by pathname (gitignored, like llms.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_tokens on hidden reasoning and return finish_reason=length with 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)

  • Generated quality is page-specific — Releases: "What happens on a failed cast?", "How to rollback a release?"; Namespaces: "Can secrets cross namespaces?"
  • Frontmatter questions render only on their page (checked via served HTML)
  • Cache no-op on rebuild; tsc/lint clean; production build green (78 pages)

…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).
Base automatically changed from feat/ai-composer-textarea-attachments to main June 11, 2026 16:15
@oreofeolurin
oreofeolurin merged commit d56409a into main Jun 11, 2026
1 check passed
@oreofeolurin
oreofeolurin deleted the feat/ai-page-suggestions branch June 11, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant