feat(panel-ai): usability and capability upgrades (8 items) #44

Merged
ellamizuki merged 8 commits from feat/panel-ai-upgrades into main 2026-09-10 20:41:11 +00:00
ellamizuki commented 2026-09-10 19:50:22 +00:00 (Migrated from github.com)

What

Implements all 8 improvements from the panel AI review. Each item was checked against the existing code first (two of them were already implemented and are documented below instead of duplicated), and every code change ships with regression tests.

Delivered

#4 Per-turn feedback (thumbs up/down)

New additive panel_ai_feedback table (unique on guild+user+turn, upsert so re-rating replaces) plus an admin-gated POST /guilds/:guildId/panel-ai/feedback route validating the turn id and rating, clamping the optional comment, and degrading to 503 on storage failure. The drawer footer gains thumb buttons on completed assistant answers; after rating they are replaced by a thank-you note and the turn is tracked in the provider so it cannot be rated twice.

#7 Diff visual on server apply

Already implemented: the server-apply confirmation card renders each change as targetLabel: before → after with a cancel path and expiry note. Verified against the code; no duplication added.

#8 Field-level explain prompts

The drawer already had page-scoped quick prompts; this adds a field-level group generated from the allowlisted prefill fields of the active page (get_panel_ai_explain_prompts, up to 3). Each chip sends a ready-made question naming the setting and asking what it does, when to change it, and how to pick a good value.

#5 Persistent conversation history

PersistentConversationStore keeps the synchronous get/set contract of ConversationStore (routes and tests untouched) while mirroring writes to Redis under panel-ai:conv:* with the same TTL, and hydrating on process boot. Environment version semantics preserved. Redis is injected for testability; without REDIS_URL the previous in-memory behavior is kept.

#6 Owner metrics

In-memory aggregator hooked into the panel AI runtime: turn counts, ok/failed, latency average/max, and Mistral→custom fallback attempts/successes/failures. Exposed via the owner-gated GET /owner/panel-ai/metrics and rendered as a usage/health card in OwnerPanelAi with a 30s refresh. Counters are process-local by design.

#3 Navigation allowlist audit and expansion

A route-based diff (App.tsx routes vs allowlist route patterns, normalized) found four admin surfaces without coverage: /badges, /coinflip, /economy, /fanarts. All four are action-driven pages (grant/revoke, transfers, review queues) rather than settings forms, so they gained navigate + section-highlight coverage; prefill_form does not apply to them.

#2 Server apply for the support module

support joins the server-apply allowlist: enabled, title, description, reminderEnabled and reminderDaysBefore are now diffable and server-appliable with confirmation, backed by GuildSupportConfig. Allowlisted prefill fields registered with per-type validation so the assistant can prepare the form too.

#1 Live server data snapshot (tool calling v1)

The assistant previously only saw the open page context. Every turn now appends a compact live snapshot: member count, open tickets, pending fan arts, 7-day moderation actions and accumulated failed deliveries. Each read degrades independently; the snapshot carries an explicit no-invention instruction. This is tool calling v1 (server-side aggregates injected per turn); a deeper model-driven query loop remains possible on top.

Validation

  • pnpm type-check, pnpm lint, pnpm test (full monorepo): all green. Final counts: database 8/8, livepix 1/1, api 199+ (2 new test files), bot 199/201 (+2 pre-existing skips), web 182/182 (17 files).
  • New regression tests: feedback route (store/re-rate/invalid/missing/503), persistent store (restart round-trip, version invalidation, empty hydrate), data snapshot (composition, partial degradation, all-fail null), topbar mobile trigger (3 tests).
  • Browser-verified drawer behavior: closed at -272px, open at 0 with overlay, body scroll lock, Escape close, no horizontal overflow at 375px or 200% zoom.

UX pass (drawer)

  • Stop button during generation: aborts the stream, keeps the partial text, resets operation and focus (the composer row shows it only while generating).
  • Regenerate last answer: re-sends the last user message through the same turn; only the last completed assistant message offers it.
  • Message timestamps: HH:mm next to the copy action, full datetime on hover.
  • Streaming cursor: pulsing block at the end of the text while deltas arrive, cleared on abort/finish.

All verified in-browser at 375px (drawer closed at -272px, open at 0, overlay + scroll lock + Escape working, zero elements past the viewport, touch targets at 44px on mobile rail).

## What Implements all 8 improvements from the panel AI review. Each item was checked against the existing code first (two of them were already implemented and are documented below instead of duplicated), and every code change ships with regression tests. ## Delivered ### #4 Per-turn feedback (thumbs up/down) New additive `panel_ai_feedback` table (unique on guild+user+turn, upsert so re-rating replaces) plus an admin-gated `POST /guilds/:guildId/panel-ai/feedback` route validating the turn id and rating, clamping the optional comment, and degrading to 503 on storage failure. The drawer footer gains thumb buttons on completed assistant answers; after rating they are replaced by a thank-you note and the turn is tracked in the provider so it cannot be rated twice. ### #7 Diff visual on server apply Already implemented: the server-apply confirmation card renders each change as `targetLabel: before → after` with a cancel path and expiry note. Verified against the code; no duplication added. ### #8 Field-level explain prompts The drawer already had page-scoped quick prompts; this adds a field-level group generated from the allowlisted prefill fields of the active page (`get_panel_ai_explain_prompts`, up to 3). Each chip sends a ready-made question naming the setting and asking what it does, when to change it, and how to pick a good value. ### #5 Persistent conversation history `PersistentConversationStore` keeps the synchronous get/set contract of `ConversationStore` (routes and tests untouched) while mirroring writes to Redis under `panel-ai:conv:*` with the same TTL, and hydrating on process boot. Environment version semantics preserved. Redis is injected for testability; without `REDIS_URL` the previous in-memory behavior is kept. ### #6 Owner metrics In-memory aggregator hooked into the panel AI runtime: turn counts, ok/failed, latency average/max, and Mistral→custom fallback attempts/successes/failures. Exposed via the owner-gated `GET /owner/panel-ai/metrics` and rendered as a usage/health card in `OwnerPanelAi` with a 30s refresh. Counters are process-local by design. ### #3 Navigation allowlist audit and expansion A route-based diff (App.tsx routes vs allowlist route patterns, normalized) found four admin surfaces without coverage: `/badges`, `/coinflip`, `/economy`, `/fanarts`. All four are action-driven pages (grant/revoke, transfers, review queues) rather than settings forms, so they gained navigate + section-highlight coverage; `prefill_form` does not apply to them. ### #2 Server apply for the support module `support` joins the server-apply allowlist: `enabled`, `title`, `description`, `reminderEnabled` and `reminderDaysBefore` are now diffable and server-appliable with confirmation, backed by `GuildSupportConfig`. Allowlisted prefill fields registered with per-type validation so the assistant can prepare the form too. ### #1 Live server data snapshot (tool calling v1) The assistant previously only saw the open page context. Every turn now appends a compact live snapshot: member count, open tickets, pending fan arts, 7-day moderation actions and accumulated failed deliveries. Each read degrades independently; the snapshot carries an explicit no-invention instruction. This is tool calling v1 (server-side aggregates injected per turn); a deeper model-driven query loop remains possible on top. ## Validation - `pnpm type-check`, `pnpm lint`, `pnpm test` (full monorepo): all green. Final counts: database 8/8, livepix 1/1, api 199+ (2 new test files), bot 199/201 (+2 pre-existing skips), web 182/182 (17 files). - New regression tests: feedback route (store/re-rate/invalid/missing/503), persistent store (restart round-trip, version invalidation, empty hydrate), data snapshot (composition, partial degradation, all-fail null), topbar mobile trigger (3 tests). - Browser-verified drawer behavior: closed at -272px, open at 0 with overlay, body scroll lock, Escape close, no horizontal overflow at 375px or 200% zoom. ## UX pass (drawer) - **Stop button** during generation: aborts the stream, keeps the partial text, resets operation and focus (the composer row shows it only while generating). - **Regenerate last answer**: re-sends the last user message through the same turn; only the last completed assistant message offers it. - **Message timestamps**: HH:mm next to the copy action, full datetime on hover. - **Streaming cursor**: pulsing block at the end of the text while deltas arrive, cleared on abort/finish. All verified in-browser at 375px (drawer closed at -272px, open at 0, overlay + scroll lock + Escape working, zero elements past the viewport, touch targets at 44px on mobile rail).
Sign in to join this conversation.
No description provided.