You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[feat](chat): AI Advisor — context-aware, client-side chatbot (Phase 3)
A grounded, offline, rule-based assistant built on the Adapter Pattern.
Engine/state (decoupled, src/lib/chat/):
- ChatAdapter contract + getChatAdapter() single swap-point; localAdvisorAdapter
answers from the FROZEN engine + config (answerText() pure, unit-tested) so it
can never contradict the model or fabricate. Network LLM = drop-in later, zero
UI change. Streams via AsyncIterable under an AbortSignal.
- buildChatContext(): structuredClone deep-clone + dependency-free validation;
invalid/partial input → complete moderate baseline (no undefined/crash).
- useChat: throttled submits + ignore-while-streaming (no spam), stop/regenerate/
abort, hydration-safe persistence, cross-tab reset via BroadcastChannel.
UI (lazy, src/components/chat/):
- ChatFab (lazy) → ChatMount → ChatPanel; memoized bubbles render via the
existing dependency-free XSS-safe-by-construction markdown renderer, each in a
per-bubble ErrorBoundary. Smart-scroll (IntersectionObserver, pauses on manual
scroll-up), streaming caret, Stop/Regenerate, suggestions, full a11y
(labelled dialog, polite live region, keyboard), EN/ID.
Wiring (anti-regression): FAB mounted GLOBALLY so tab-switch closes the Guide but
never unmounts chat / disrupts a stream; "Start Over" wipes chat + broadcasts.
Bundle: FAB + all chat lazy → INITIAL budget untouched (119.9/120); total 260→268
(documented). Browser-verified: grounded /100 reply, survives nav, reset wipes, EN/ID.
145 unit (+17) + 14 e2e, tsc, lint, all 6 guards green. README Phase 3 section +
Mermaid + adapter integration snippet; DECISIONS records the two reconciliations.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: scripts/check-bundle-size.mjs
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -17,7 +17,7 @@ import { gzipSync } from 'node:zlib';
17
17
// shared async chunk can't silently be mis-counted. Headroom catches a real regression; raise the
18
18
// budgets deliberately (with a note) if the app grows.
19
19
constJS_INITIAL_BUDGET_KB=120;
20
-
constJS_TOTAL_BUDGET_KB=260;// raised 200→260 for full Insights bilingualisation 2026-07-15 (6 datasets + 18 article bodies now carry EN+ID; all in the lazy content chunk — initial budget untouched; NFR cap is 300)
20
+
constJS_TOTAL_BUDGET_KB=268;// raised 200→260 (Insights bilingualisation 2026-07-15); 260→268 for the Phase 3 AI Advisor chat 2026-07-19 (adapter + hook + panel, all in a LAZY chunk — the FAB is lazy too, so the initial budget is untouched; NFR cap is 300)
21
21
constCSS_BUDGET_KB=27;// raised 25→27 for Fase 2g UI/UX polish 2026-07-18 (preset dropdown, uniform export buttons, 2×2 step-rail wrap grid, footer stacking, modern app-bar controls); still well under the ~30kB NFR ceiling
0 commit comments