Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ client.on('interactionCreate', async (interaction) => {
});

/**
* Graceful shutdown handler
* @param {string} signal - Signal that triggered shutdown
* Perform an orderly shutdown: stop background services, persist in-memory state, remove logging transport, close the database pool, disconnect the Discord client, and exit the process.
* @param {string} signal - The signal name that initiated shutdown (e.g., "SIGINT", "SIGTERM").
*/
async function gracefulShutdown(signal) {
info('Shutdown initiated', { signal });
Expand Down Expand Up @@ -280,13 +280,7 @@ if (!token) {
}

/**
* Main startup sequence
* 1. Initialize database
* 2. Load config from DB (seeds from config.json if empty)
* 3. Load previous conversation state
* 4. Register event handlers with live config
* 5. Load commands
* 6. Login to Discord
* Perform full application startup: initialize the database and optional PostgreSQL logging, load configuration and conversation history, start background services (conversation cleanup, memory checks, triage, tempban scheduler), register event handlers, load slash commands, and log the Discord client in.
*/
async function startup() {
// Initialize database
Expand Down Expand Up @@ -379,4 +373,4 @@ async function startup() {
startup().catch((err) => {
error('Startup failed', { error: err.message, stack: err.stack });
process.exit(1);
});
});
39 changes: 20 additions & 19 deletions src/modules/ai.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,10 @@ export function getConversationHistory() {
}

/**
* Set the conversation history map (for state restoration)
* @param {Map} history - Conversation history map to restore
* Replace the in-memory conversation history with the provided map.
*
* Also clears any pending hydration promises to avoid stale in-flight hydrations.
* @param {Map} history - Map from channelId (string) to an array of message objects representing each channel's history.
*/
export function setConversationHistory(history) {
conversationHistory = history;
Expand Down Expand Up @@ -336,8 +338,9 @@ export function stopConversationCleanup() {
}

/**
* Run a single cleanup pass
* @returns {Promise<void>}
* Delete conversation records older than the configured history TTL from the database.
*
* If no database pool is configured this is a no-op; failures are logged but not thrown.
*/
async function runCleanup() {
const pool = getPool();
Expand All @@ -363,22 +366,20 @@ async function runCleanup() {
}

/**
* Generate AI response using the Claude Agent SDK.
* Generate an AI reply for a channel message using the Claude Agent SDK, integrating short-term history and optional user memory.
*
* Memory integration:
* - Pre-response: searches mem0 for relevant user memories and appends them to the system prompt.
* - Post-response: fires off memory extraction (non-blocking) so new facts get persisted.
* Pre-response: may append a short, relevant memory context scoped to `userId` to the system prompt. Post-response: triggers asynchronous extraction and storage of memorable facts.
*
* @param {string} channelId - Channel ID
* @param {string} userMessage - User's message
* @param {string} username - Username
* @param {Object} config - Bot configuration
* @param {Object} healthMonitor - Health monitor instance (optional)
* @param {string} [userId] - Discord user ID for memory scoping
* @param {Object} [options] - SDK options
* @param {string} [options.model] - Model override
* @param {number} [options.maxThinkingTokens] - Max thinking tokens override
* @returns {Promise<string>} AI response
* @param {string} channelId - Conversation channel identifier.
* @param {string} userMessage - The user's message text.
* @param {string} username - Display name to attribute user messages in history.
* @param {Object} config - Bot configuration object (controls model defaults, timeouts, budgets, and prompts).
* @param {Object} [healthMonitor] - Optional health monitor; if provided, request/result status and counts will be recorded.
* @param {string} [userId] - Optional user identifier used to scope memory lookups and post-response memory extraction.
* @param {Object} [options] - Optional SDK overrides.
* @param {string} [options.model] - Model identifier to override the configured default.
* @param {number} [options.maxThinkingTokens] - Override for the SDK's thinking-token budget.
* @returns {string} The assistant's reply text.
*/
export async function generateResponse(
channelId,
Expand Down Expand Up @@ -502,4 +503,4 @@ You can use Discord markdown formatting.`;
}
return "Sorry, I'm having trouble thinking right now. Try again in a moment!";
}
}
}
21 changes: 13 additions & 8 deletions src/modules/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ import { recordCommunityActivity, sendWelcomeMessage } from './welcome.js';
let processHandlersRegistered = false;

/**
* Register bot ready event handler
* @param {Client} client - Discord client
* @param {Object} config - Bot configuration
* @param {Object} healthMonitor - Health monitor instance
* Register a one-time handler that runs when the Discord client becomes ready.
*
* When fired, the handler logs the bot's online status and server count, records
* start time with the provided health monitor (if any), and logs which features
* are enabled (welcome messages with channel ID, AI triage model selection, and moderation).
*
* @param {Client} client - The Discord client instance.
* @param {Object} config - Bot configuration object (may include `welcome`, `ai`, `triage`, and `moderation` settings).
* @param {Object} [healthMonitor] - Optional health monitor with a `recordStart` method to mark service start time.
*/
export function registerReadyHandler(client, config, healthMonitor) {
client.once(Events.ClientReady, () => {
Expand All @@ -46,9 +51,9 @@ export function registerReadyHandler(client, config, healthMonitor) {
}

/**
* Register guild member add event handler
* @param {Client} client - Discord client
* @param {Object} config - Bot configuration
* Register a handler that sends the configured welcome message when a user joins a guild.
* @param {Client} client - Discord client instance to attach the event listener to.
* @param {Object} config - Bot configuration containing welcome settings.
*/
export function registerGuildMemberAddHandler(client, config) {
client.on(Events.GuildMemberAdd, async (member) => {
Expand Down Expand Up @@ -176,4 +181,4 @@ export function registerEventHandlers(client, config, healthMonitor) {
registerGuildMemberAddHandler(client, config);
registerMessageCreateHandler(client, config, healthMonitor);
registerErrorHandlers(client);
}
}
Loading
Loading