Drop 3 columns that were written but never read: - ai_moderation_raw: raw LLM JSON response (~KB per message, never consumed) - ai_policy_version: hardcoded 'default-2026-05-30', never used for decisions - ai_evidence: JSON evidence array, never read after write Changes: - schema.ts: remove columns from both Postgres and SQLite table definitions - messageStore.ts: remove from AIAnalysisUpdate interface and SET clauses - aiAnalyzer.ts: remove from individual fallback update calls - aiAnalysisWorker.ts: remove raw write, add missing fields (categories, severity, etc.) - types.ts: remove from MessageRecord interface - analysisRoutes.ts: remove from reset analysis call - New migration: src/database/migrations/001_drop_unused_ai_columns.sql - Migration applied to live DB: 27 columns → 24 columns Kept ai_error (useful for future debugging, currently 0 non-null) Kept metadata (1.9MB total, used for AI sticker/embed evidence analysis) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
212 lines
5.1 KiB
TypeScript
212 lines
5.1 KiB
TypeScript
import type {
|
|
BroadcasterClient,
|
|
ModerationBroadcaster,
|
|
} from "./broadcaster.js";
|
|
|
|
export type AIStatus = "pending" | "clean" | "warn" | "flagged" | "error";
|
|
export type AISeverity = "none" | "low" | "medium" | "high" | "critical";
|
|
export type AIRecommendedAction =
|
|
| "none"
|
|
| "monitor"
|
|
| "warn"
|
|
| "review"
|
|
| "delete"
|
|
| "escalate";
|
|
|
|
export type { BroadcasterClient, ModerationBroadcaster };
|
|
|
|
export interface MessageRecord {
|
|
id: string;
|
|
guild_id: string;
|
|
channel_id: string;
|
|
thread_id: string | null;
|
|
user_id: string;
|
|
username: string;
|
|
avatar_url: string | null;
|
|
content: string;
|
|
edited_content: string | null;
|
|
created_at: number;
|
|
edited_at: number | null;
|
|
deleted_at: number | null;
|
|
type: "text" | "edited" | "deleted";
|
|
metadata: string | null;
|
|
ai_status?: AIStatus | null;
|
|
ai_moderation_flags?: string | null;
|
|
ai_moderation_score?: number | null;
|
|
ai_analysis?: string | null;
|
|
ai_categories?: string | null;
|
|
ai_severity?: AISeverity | null;
|
|
ai_confidence?: number | null;
|
|
ai_recommended_action?: AIRecommendedAction | null;
|
|
ai_analyzed_at?: number | null;
|
|
ai_error?: string | null;
|
|
}
|
|
|
|
export interface AttachmentRecord {
|
|
id: string;
|
|
message_id: string;
|
|
guild_id: string;
|
|
channel_id: string;
|
|
thread_id: string | null;
|
|
user_id: string;
|
|
filename: string;
|
|
size: number;
|
|
type: string;
|
|
discord_url: string;
|
|
uploaded_url: string | null;
|
|
upload_status: "pending" | "uploaded" | "failed";
|
|
upload_error: string | null;
|
|
created_at: number;
|
|
uploaded_at: number | null;
|
|
}
|
|
|
|
export interface VoiceSegmentRecord {
|
|
id: string;
|
|
user_id: string;
|
|
session_id: string;
|
|
guild_id: string;
|
|
channel_id: string;
|
|
filename: string;
|
|
duration_ms: number;
|
|
created_at: number;
|
|
}
|
|
|
|
export interface DashboardMessage {
|
|
id: string;
|
|
channel_id: string;
|
|
user_id: string;
|
|
username: string;
|
|
avatar_url: string | null;
|
|
content: string;
|
|
created_at: number;
|
|
type: "text" | "image" | "voice";
|
|
}
|
|
|
|
export interface MessageQuery {
|
|
guildId?: string;
|
|
channelId?: string;
|
|
threadId?: string;
|
|
status?: AIStatus[];
|
|
userId?: string;
|
|
q?: string;
|
|
cursor?: string;
|
|
limit: number;
|
|
}
|
|
|
|
export interface PageResult<T> {
|
|
data: T[];
|
|
nextCursor: string | null;
|
|
}
|
|
|
|
export interface AnalysisResult {
|
|
messageId: string;
|
|
status: Exclude<AIStatus, "pending">;
|
|
flags: string[];
|
|
score: number;
|
|
analysis: string;
|
|
categories?: string[];
|
|
severity?: AISeverity;
|
|
confidence?: number;
|
|
recommendedAction?: AIRecommendedAction;
|
|
policyVersion?: string;
|
|
evidence?: string[];
|
|
}
|
|
|
|
export type MediaMode = "music" | "screen";
|
|
export type MediaSourceKind =
|
|
| "url"
|
|
| "local"
|
|
| "youtube"
|
|
| "spotify"
|
|
| "search";
|
|
export type MediaQueueItemStatus = "queued" | "playing" | "failed";
|
|
|
|
export interface MediaQueueItem {
|
|
id: string;
|
|
mode: MediaMode;
|
|
source: string;
|
|
title: string;
|
|
kind: MediaSourceKind;
|
|
requestedBy: string;
|
|
addedAt: number;
|
|
status: MediaQueueItemStatus;
|
|
}
|
|
|
|
export interface MediaState {
|
|
playing: boolean;
|
|
musicVolume: number;
|
|
current: MediaQueueItem | null;
|
|
queue: MediaQueueItem[];
|
|
}
|
|
|
|
export type ModerationWsEvent =
|
|
| { type: "ui_state"; state: unknown }
|
|
| { type: "user_state"; users: unknown[] }
|
|
| { type: "message_created"; data: MessageRecord }
|
|
| { type: "message_updated"; data: Partial<MessageRecord> & { id: string } }
|
|
| { type: "message_deleted"; data: { id: string; deleted_at: number } }
|
|
| { type: "message_analyzed"; data: MessageRecord }
|
|
| { type: "attachment_created"; data: AttachmentRecord }
|
|
| { type: "analysis_queue_status"; data: AnalysisQueueStatus }
|
|
| { type: "media_state"; state: MediaState }
|
|
| { type: "voice_recording_uploaded"; data: any };
|
|
|
|
export interface AnalysisQueueStatus {
|
|
queuedConversations: number;
|
|
activeRequests: number;
|
|
/** Number of single-message fallback calls currently awaiting the LLM. */
|
|
activeIndividualRequests: number;
|
|
/** Number of message IDs sitting in the dedup set (in-flight or about to start). */
|
|
individualInFlightCount: number;
|
|
/** True when the individual-fallback circuit breaker is tripped. */
|
|
individualCircuitBreakerActive: boolean;
|
|
lastError: string | null;
|
|
}
|
|
|
|
export type ReviewStatus = "pending" | "approved" | "rejected" | "escalated";
|
|
|
|
export interface MessageReview {
|
|
id: string;
|
|
message_id: string;
|
|
guild_id: string;
|
|
channel_id: string;
|
|
reviewer_id: string | null;
|
|
status: ReviewStatus;
|
|
notes: string | null;
|
|
created_at: number;
|
|
reviewed_at: number | null;
|
|
}
|
|
|
|
export type ModerationActionType =
|
|
| "delete_message"
|
|
| "mute_user"
|
|
| "warn_user"
|
|
| "kick_user"
|
|
| "ban_user";
|
|
|
|
export interface ModerationAction {
|
|
id: string;
|
|
message_id: string | null;
|
|
user_id: string | null;
|
|
guild_id: string;
|
|
action_type: ModerationActionType;
|
|
reason: string | null;
|
|
executed_by: string | null;
|
|
status: "pending" | "executed" | "failed";
|
|
error: string | null;
|
|
created_at: number;
|
|
executed_at: number | null;
|
|
}
|
|
|
|
export interface RetentionPolicy {
|
|
id: string;
|
|
guild_id: string;
|
|
channel_id: string | null;
|
|
retention_days: number;
|
|
apply_to_media: boolean;
|
|
apply_to_voice: boolean;
|
|
enabled: boolean;
|
|
created_at: number;
|
|
updated_at: number;
|
|
}
|