Commit Graph
216 Commits
Author SHA1 Message Date
MythEclipse 394bd5a471 feat(moderation): skip message capture for specific channels in shouldCaptureMessageLocation 2026-05-30 00:37:20 +07:00
MythEclipse b938420eb3 feat(moderation): enhance Indonesian slang lexicon with additional profanity normalization and expand badword detection logic 2026-05-30 00:14:28 +07:00
MythEclipse d03244a0ae feat(moderation): update lexicon to include sexual deviation topics and clarify analysis guidelines 2026-05-30 00:01:09 +07:00
MythEclipse 81606f49a5 feat(moderation): enhance Indonesian slang lexicon with profanity normalization 2026-05-29 23:59:38 +07:00
MythEclipse 9ed50bc8ed feat(ui): add "analytics" tab to activeTabs and defaultSharedUIState 2026-05-29 21:10:00 +07:00
MythEclipse 687fcec62c chore: add comment to clarify app initialization process 2026-05-29 20:54:57 +07:00
MythEclipse 8c3bb77984 feat: add analytics hooks and routes for moderation statistics
- Implemented `useAnalytics` hook for fetching and managing analytics data.
- Created `analyticsStore.ts` to handle database queries for hourly stats, topic trends, user leaderboard, and moderation stats.
- Added Express routes for analytics endpoints including overview, hourly stats, topic trends, user leaderboard, moderation stats, and top violators.
- Introduced a utility function `filterHits` for filtering specific terms in text.
2026-05-29 19:37:08 +07:00
MythEclipseandClaude Opus 4.8 fb09ac81c5 feat(moderation): Indonesian slang normalizer and false-positive prevention
- Add indonesian-badwords dependency for local lexical signal
- Add Indonesian slang lexicon with woy/woi/hadeh as safe casual terms
- Normalize Discord custom emoji <:name:id> to [emoji:name] in prompts
- Wire normalization evidence into both conversationContext and llmModerationClient prompts
- Harden system prompt: woy/woi are casual greetings, not SARA/hate
- Add tests for emoji normalization, slang mapping, badword detection

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 18:39:10 +07:00
MythEclipse b96fb619c9 feat(config): change default value of boolean to false in config schema 2026-05-29 18:12:28 +07:00
MythEclipseandClaude Opus 4.8 7da83387ee feat(moderation): auto-delete flagged messages
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 18:04:42 +07:00
MythEclipse 649283a3bc feat(moderation): enhance media analysis handling and integrate image evidence 2026-05-29 17:43:34 +07:00
MythEclipse 2b1c436b3e feat(moderation): enhance media evidence handling and deferral analysis rejection 2026-05-29 17:32:04 +07:00
MythEclipse 441ff5a0ed feat(moderation): fetch and analyze URLs (images and web text) from messages
- Added  to safely extract and fetch up to 3 URLs per message (with SSRF protection, 5MB limit, and 8s timeout).
- Implemented recursive  extraction to resolve Tenor/Giphy links from their HTML viewers to raw GIF binaries.
- In , fetched images are automatically injected as  into the vision LLM context, and truncated webpage text is appended to the message string.
2026-05-28 01:29:31 +07:00
MythEclipse c6af313c33 fix(moderation): immediately abort retries on 429 Too Many Requests
- In llmModerationClient.ts (inner retry), if OpenAI throws a 429 (or 401/403), throw p-retry's AbortError to immediately exit the 3-attempt inner retry loop.
- In aiAnalyzer.ts (outer retry), propagate the AbortError from runModerationAnalysis so the 2-attempt outer retry loop also aborts immediately.
- This ensures that a burst of 20 concurrent tasks hitting rate limits immediately returns the messages to the DB queue (as 'analysis_incomplete') and rapidly increments the individual circuit breaker, pausing processing and preventing a thundering herd instead of making 12 API calls per stuck message.
2026-05-28 01:09:57 +07:00
MythEclipse 9976e66ca5 fix(moderation): patch 3 additional aiAnalyzer vulnerabilities
Infinite recovery loop (#new):
  - Inside retryWithBackoff callback in processIndividualFallback, detect
    'analysis_incomplete' in the LLM result and throw to trigger backoff.
  - Track exhaustedOnIncomplete flag across retries.
  - On final exhaustion: write terminal flag 'individual_analysis_exhausted'
    to DB so the recovery query (which only looks for 'analysis_incomplete')
    never picks this message up again.
  - Transient failures (network/parse) are NOT written as exhausted; they
    remain as 'analysis_incomplete' and are retried via the CB-throttled
    recovery cycle.

Token budget zero-result deadlock (#10):
  - If pickBatchWithinBudget returns [] because every candidate message
    individually exceeds AI_ANALYSIS_MAX_TARGET_TOKENS, fall back to
    messages.slice(0,1) so at least the first message is processed.
  - Without this, messages would be permanently stuck as 'pending' because
    every recovery tick would fetch them, trim to 0, and exit silently.
  - Uses messages.slice(0,1) instead of messages[0]! to avoid the
    forbidden noNonNullAssertion lint rule.

Stale state map memory leak (#9):
  - startPendingAIAnalysisWorker now prunes conversationErrorCooldown and
    conversationProcessing on every recovery interval tick.
  - Cooldown entries past their expiry timestamp are deleted.
  - Processing entries older than AI_ANALYSIS_PROCESSING_TIMEOUT_MS are
    deleted (these represent stale locks from crashed processing runs).
  - Prevents unbounded Map growth for long-running bots with many channels.

Batch/individual scheduling collision (#8):
  - Build incompleteKeySet (Set<string>) from incompleteKeys before the
    batch recovery loop.
  - Batch recovery loop skips any key present in incompleteKeySet so a
    conversation that has both 'pending' and 'analysis_incomplete' messages
    is only targeted by the individual pipeline, not both simultaneously.
  - Avoids the DB last-write-wins race where batch and individual pipelines
    both update the same message rows concurrently.
2026-05-28 00:07:55 +07:00
MythEclipse 61045aabc8 fix(moderation): patch 6 aiAnalyzer audit vulnerabilities
#1+#5 - Individual fallback circuit breaker
  - Add individualConsecutiveErrors + individualCooldownUntil (30s)
  - On success: reset counter; on failure: increment + trip at
    AI_ANALYSIS_INDIVIDUAL_CB_THRESHOLD (default 10) consecutive errors
  - enqueueIndividualFallbacks checks CB before admitting any work

#1 - Individual fallback concurrency cap
  - enqueueIndividualFallbacks enforces AI_ANALYSIS_INDIVIDUAL_MAX_CONCURRENT
    (default 20); overflow stays as error/analysis_incomplete in DB and is
    recovered by the recovery worker on the next interval

#3 - Unhandled rejection in async setTimeout
  - scheduleConversationAnalysis no longer uses async arrow in setTimeout;
    all async work is chained with .then()/.catch() explicitly

#4 - Recovery worker ignores individualInFlight
  - Add individualInFlightByConversation Map<conversationKey, count>
  - processIndividualFallback increments/decrements it in try/finally
  - startPendingAIAnalysisWorker skips conversations present in the map
  - Recovery worker also processes error/analysis_incomplete messages via
    two new messageStore queries: getConversationKeysWithIncompleteAnalysis
    and getIncompleteMessagesByConversation

#6 - pickBatchWithinBudget never called
  - scheduleConversationAnalysis now calls pickBatchWithinBudget with
    AI_ANALYSIS_MAX_TARGET_TOKENS (default 4000) + 50-token per-msg overhead
    after fetching messages, before passing to processBatch

#7 - AI_PROCESSING_OVERLAP_MS 30s shorter than max LLM retry window
  - Replace hardcoded 30 000 ms constant with configurable
    AI_ANALYSIS_PROCESSING_TIMEOUT_MS (default 120 000 ms)
  - LLM client: 30s timeout × 3 retries + backoff ≈ 90-100s; 120s is safe

New config keys:
  AI_ANALYSIS_PROCESSING_TIMEOUT_MS   (default: 120000)
  AI_ANALYSIS_INDIVIDUAL_MAX_CONCURRENT (default: 20)
  AI_ANALYSIS_INDIVIDUAL_CB_THRESHOLD  (default: 10)
  AI_ANALYSIS_MAX_TARGET_TOKENS        (default: 4000)

New AnalysisQueueStatus fields:
  activeIndividualRequests, individualInFlightCount,
  individualCircuitBreakerActive
2026-05-27 23:32:38 +07:00
MythEclipse 5925c11c54 feat(moderation): two-tier batch+individual fallback pipeline
- After a batch LLM call, any result flagged analysis_incomplete is
  immediately fanned out to an individual per-message fallback queue
- Batch hard-fail (result.ok=false) and unhandled exceptions now also
  route all affected messages to the individual queue instead of waiting
  behind the conversation error cooldown
- Individual queue runs fully parallel (fire-and-forget per message),
  de-duplicated by a Set<messageId> so no double-processing
- processIndividualFallback runs in the main process (no worker pool IPC
  overhead for a single-item call), with retryWithBackoff 2x/2-15s
- AnalysisQueueStatus gains activeIndividualRequests +
  individualInFlightCount fields for dashboard observability
2026-05-27 23:25:37 +07:00
MythEclipse c1c149855a feat: enforce strict AI env validation and force close 2026-05-26 00:59:32 +07:00
MythEclipse 7126959548 fix: bypass Cloudflare WAF 403 blocks by spoofing User-Agent and removing X-Stainless headers 2026-05-26 00:03:01 +07:00
MythEclipse cc61e2576b refactor: optimize AI moderation pipeline, fix OOM risks, token duplication, and add Zod validation 2026-05-25 23:23:12 +07:00
MythEclipse cc2ee84c3b refactor(ai-analyzer): fix resource leaks, OOM risk, and strict structured outputs 2026-05-25 22:14:05 +07:00
MythEclipse c32b5274e9 chore: update dependencies and configuration
- Added @discordjs/opus and opusscript to package.json and pnpm-lock.yaml.
- Updated pnpm-workspace.yaml to allow builds for @discordjs/opus.
- Imported dotenv in config.ts for environment variable management.
- Created .npmrc to manage npm configurations.
2026-05-24 20:06:36 +07:00
MythEclipse 4ec9b50f33 fix(moderation): interleave images with owning messages, Indonesian-first prompt
- Replace flat imageParts prologue with per-message image map (messageImageMap)
  keyed by message_id. Images are now inserted immediately after their owning
  message's text part in the multimodal content array, giving the vision model
  proper text+image co-context instead of a disconnected image dump before the
  entire prompt.

- Rewrite moderationPrompt as Indonesian-first bilingual system prompt:
  * Primary language: Bahasa Indonesia; English secondary
  * Explicit Discord community context with Indonesian slang awareness
    (anjay, wkwk, santuy, gw/lo abbreviations, etc.)
  * SARA, hoaks, ujaran kebencian cultural context
  * Charitable intent for ambiguous Indonesian phrasing
  * Expanded flag taxonomy: sara, hoaks, nsfw_image, gore_image, doxxing, scam
  * analysis field instructed in Bahasa Indonesia (maks 2 kalimat)
  * Retry/correction messages also in Bahasa Indonesia

- Image instruction block conditionally injected into prompt only when
  hasImages=true, explicitly telling model to treat image + preceding text
  as one semantic unit and to OCR meme/screenshot text as message content.
2026-05-22 01:04:00 +07:00
MythEclipse d0e906763e fix(moderation): fix image attachment pipeline causing PIL BadRequestError on NVIDIA inference
Three-layer defect chain causing 'cannot identify image file <_io.BytesIO object>':

1. attachmentUploader: hardcoded 'application/octet-stream' on Tele CDN upload
   regardless of actual file MIME type — CDN stored images under wrong type.

2. messageCapture: processAttachmentUpload call site never forwarded
   attachment.contentType into the options bag, so the fix in (1) would
   have received undefined and fallen back to octet-stream anyway.

3. llmModerationClient: blindly trusted att.type from the DB record
   (Discord-provided MIME) when constructing data: URLs, but validated
   neither the HTTP status of the CDN re-fetch nor the actual byte content.
   Stale/expired CDN URLs returning HTML error pages were base64-encoded
   and sent to the model as 'image/jpeg', causing PIL to reject the stream.

Fixes:
- uploadAttachmentToTele now accepts contentType param (defaults to
  application/octet-stream for non-image files)
- processAttachmentUpload options bag gains optional contentType field
- messageCapture forwards attachment.contentType at the call site
- Added sniffImageMimeType() using magic-byte probes for JPEG, PNG, GIF,
  WebP, AVIF/HEIF — runs on every downloaded attachment buffer before
  base64 encoding; skips the attachment (logs headerHex for diagnosis)
  if bytes don't match a known image format
- data: URL now uses the sniffed MIME type, not the DB record
2026-05-21 23:44:18 +07:00
Asep Haryana Saputra d76549f94a refactor(app): simplify path handling for static files and index.html 2026-05-21 12:35:28 +00:00
Asep Haryana Saputra 41197fd2c2 feat(build): optimize Dockerfile to build vendor packages during image build and streamline package.json scripts 2026-05-21 12:27:07 +00:00
Asep Haryana Saputra 0ef6fc8d31 refactor: update import statements to use .js extensions
- Changed all import statements across the project to include the .js extension for consistency and to comply with ES module standards.
- Updated imports in various files including bootstrap.ts, shutdown.ts, config.ts, and many others.
- Ensured that all related modules and types are correctly imported with the new extension.
2026-05-21 12:03:31 +00:00
Asep Haryana Saputra 4cd92303ef fix(config): correct regex for DISCORD_TOKEN transformation to remove quotes
fix(moderation): update import statement for pagination to include file extension
2026-05-21 11:46:08 +00:00
Asep Haryana Saputra 37cb177b11 feat(config): enhance DISCORD_TOKEN validation by trimming quotes 2026-05-21 11:40:02 +00:00
MythEclipse 834b19b1ae feat(moderation): enhance JSON extraction and validation in moderation analysis 2026-05-21 04:23:01 +07:00
MythEclipse f851ea0fa9 fix(moderation): improve error handling for malformed JSON responses and ensure proper response headers 2026-05-21 04:00:36 +07:00
MythEclipse 5588ece6c7 feat(moderation): normalize JSON response handling and enhance test coverage for moderation analysis 2026-05-21 03:52:51 +07:00
MythEclipse c1c3c99686 feat(moderation): improve message analysis scheduling and update moderation prompt structure 2026-05-21 02:56:41 +07:00
MythEclipse 7eb01606b7 feat(moderation): enhance attachment handling and AI analysis integration 2026-05-21 02:39:28 +07:00
MythEclipse 3d64228d6a feat(config): add AI analysis tuning parameters and update related logic 2026-05-21 01:55:50 +07:00
MythEclipse c349736b89 refactor(messageStore): simplify message query conditions and pagination logic
chore(package): remove unused pnpm configuration
2026-05-21 00:45:35 +07:00
MythEclipse 480bcff5e2 feat(logging): add error serialization and log metadata formatting
- Introduced `loggerSerialization.ts` to handle error serialization and log metadata formatting.
- Added `serializeError` function to convert Error objects into a structured format.
- Implemented `serializeLogValue` to handle various data types including Errors, Dates, RegExps, and plain objects.
- Created `formatLogMetadata` to format log metadata using the serialization functions.

feat(pagination): implement cursor encoding and decoding

- Added `pagination.ts` to manage cursor-based pagination.
- Implemented `encodeCursor` to convert cursor data into a base64 string.
- Developed `decodeCursor` to parse base64 strings back into cursor data, with error handling for invalid inputs.
2026-05-21 00:34:30 +07:00
MythEclipse e8e0697a84 chore: clean dependencies and format restructure 2026-05-19 15:12:09 +07:00
MythEclipse dcbe204795 refactor: extract application bootstrap 2026-05-19 15:08:02 +07:00
MythEclipse f7c8257ef1 refactor: move webserver orchestration 2026-05-19 14:58:09 +07:00
MythEclipseandClaude Opus 4.7 d98bf1a5fe refactor: extract http app setup
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 14:52:52 +07:00
MythEclipse 109a6825bc refactor: extract websocket server 2026-05-19 14:45:39 +07:00
MythEclipse d52803ae20 refactor: extract browser audio bridge 2026-05-19 14:34:24 +07:00
MythEclipse c3f7291543 refactor: isolate websocket globals 2026-05-19 14:26:06 +07:00
MythEclipse 3639028f6f refactor: extract media settings state 2026-05-19 14:16:00 +07:00
MythEclipse a1b85d8ac3 refactor: extract persisted ui state 2026-05-19 14:11:09 +07:00
MythEclipse f48f62893d refactor: extract pcm audio helpers 2026-05-19 13:56:36 +07:00
MythEclipse 7f5db953fa chore: update dependencies and improve code formatting
- Added `vendor/discord-video-stream` to pnpm workspace.
- Refactored `llmModerationClient.ts` for better readability and consistency.
- Adjusted imports in `recordingsRoutes.ts` for clarity.
- Updated `webserver.ts` to correctly import `createRecordingsRoutes`.
- Enhanced test cases in `llmModerationClient.test.ts` for improved readability.
- Updated submodule references for `better-sqlite3`, `discord-video-stream`, `discord.js-selfbot-v13`, `drizzle-orm`, and `node-datachannel`.
- Created documentation for deprecated dependency removal plan and design.
2026-05-19 02:49:55 +07:00
MythEclipse e85967ae51 style: format winston logger changes 2026-05-19 02:48:37 +07:00
MythEclipse f8ba4b41e9 fix: preserve structured logger metadata 2026-05-19 02:43:52 +07:00