feat(ui): add Adaptive Prompt Tuner tab with correction submission UI

- Add pgCorrectedModerationsTable to shared schema
- Create backend corrections module (stats, list, create endpoints)
- Add TunerPanel with Stats, History, and Submit sub-tabs
- Add AuthOverlay gate for Tuner (admin-only, same as Live)
- Set messages as default tab
- Wire Tuner into sidebar, header, and mobile tab bar

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-12 21:28:05 +07:00
co-authored by Claude
parent fbc2184c6e
commit 7f3eb7b9ac
16 changed files with 1060 additions and 5 deletions
+48 -2
View File
@@ -118,7 +118,7 @@ export interface UIState {
selectedTextChannel?: string;
selectedAnalyticsGuild?: string;
selectedAnalyticsChannel?: string;
activeTab?: "live" | "messages";
activeTab?: "live" | "messages" | "tuner";
isListening?: boolean;
isStreaming?: boolean;
}
@@ -131,7 +131,7 @@ export interface ChatResponse {
response?: string;
}
export type DashboardTab = "live" | "messages";
export type DashboardTab = "live" | "messages" | "tuner";
// ─── Messages ────────────────────────────────────────────────────────────────
@@ -272,6 +272,52 @@ export function login(password: string): Promise<{ ok: boolean }> {
});
}
// ─── Corrections (Adaptive Prompt Tuner) ──────────────────────────────────────
export interface CorrectionStats {
total_corrections: number;
recent_count_7d: number;
by_flag: Array<{ flag: string; count: number }>;
}
export interface CorrectionEntry {
id: string;
message_id: string;
original_flags: string;
corrected_flags: string;
correction_notes: string | null;
content_snippet: string;
created_at: number;
}
export function getCorrectionStats(): Promise<CorrectionStats> {
return request<CorrectionStats>("/api/corrections/stats");
}
export function listCorrections(
params: { limit?: number; cursor?: string } = {},
): Promise<{ data: CorrectionEntry[]; nextCursor: string | null }> {
const sp = new URLSearchParams();
if (params.limit) sp.set("limit", String(params.limit));
if (params.cursor) sp.set("cursor", params.cursor);
return request<{ data: CorrectionEntry[]; nextCursor: string | null }>(
`/api/corrections?${sp}`,
);
}
export function submitCorrection(data: {
message_id: string;
original_flags: string[];
corrected_flags: string[];
correction_notes?: string;
content_snippet: string;
}): Promise<CorrectionEntry> {
return request<CorrectionEntry>("/api/corrections", {
method: "POST",
body: JSON.stringify(data),
});
}
// ─── UI State ────────────────────────────────────────────────────────────────
export function getUIState(): Promise<UIState> {
@@ -1,10 +1,11 @@
import { MessageSquare, Radio } from "lucide-react";
import { MessageSquare, Radio, SlidersHorizontal } from "lucide-react";
import type { DashboardTab } from "../../entities/ui/types";
import { cn } from "../lib/utils";
const tabs: Array<{ id: DashboardTab; label: string; Icon: typeof Radio }> = [
{ id: "live", label: "Live", Icon: Radio },
{ id: "messages", label: "Messages", Icon: MessageSquare },
{ id: "tuner", label: "Tuner", Icon: SlidersHorizontal },
];
interface MobileTabBarProps {