/** * Discord Manager Module * * Manages Discord connectors for agents that have `chat.discord` configured. * This module is responsible for: * - Creating one DiscordConnector instance per Discord-enabled agent * - Managing connector lifecycle (start/stop) * - Providing access to connectors for status queries * * @module manager */ import type { ChatManagerConnectorState, FleetManagerContext, IChatManager } from "@herdctl/core"; import { DiscordConnector } from "./discord-connector.js"; import type { DiscordReplyPayload } from "./types.js"; /** * DiscordManager handles Discord connections for agents * * This class encapsulates the creation and lifecycle management of * DiscordConnector instances for agents that have Discord chat configured. * * Implements IChatManager so FleetManager can interact with it through * the generic chat manager interface. */ export declare class DiscordManager implements IChatManager { private ctx; private connectors; private activeJobsByChannel; private lastPromptByChannel; private lastUsageByChannel; private cumulativeUsageByAgent; private initialized; constructor(ctx: FleetManagerContext); /** * Initialize Discord connectors for all configured agents * * This method: * 1. Iterates through agents to find those with Discord configured * 2. Creates a DiscordConnector for each Discord-enabled agent * * Should be called during FleetManager initialization. */ initialize(): Promise; /** * Connect all Discord connectors * * Connects each connector to the Discord gateway and subscribes to events. * Errors are logged but don't stop other connectors from connecting. */ start(): Promise; /** * Disconnect all Discord connectors gracefully * * Sessions are automatically persisted to disk on every update, * so they survive bot restarts. This method logs session state * before disconnecting for monitoring purposes. * * Errors are logged but don't prevent other connectors from disconnecting. */ stop(): Promise; /** * Get a connector for a specific agent * * @param qualifiedName - Qualified name of the agent (e.g., "herdctl.security-auditor") * @returns The DiscordConnector instance, or undefined if not found */ getConnector(qualifiedName: string): DiscordConnector | undefined; /** * Get all connector names * * @returns Array of agent qualified names that have Discord connectors */ getConnectorNames(): string[]; /** * Get the number of active connectors * * @returns Number of connectors that are currently connected */ getConnectedCount(): number; /** * Check if the manager has been initialized */ isInitialized(): boolean; /** * Check if a specific agent has a Discord connector * * @param qualifiedName - Qualified name of the agent (e.g., "herdctl.security-auditor") * @returns true if the agent has a Discord connector */ hasConnector(qualifiedName: string): boolean; /** * Check if a specific agent has a connector (alias for hasConnector) * * @param qualifiedName - Qualified name of the agent (e.g., "herdctl.security-auditor") * @returns true if the agent has a connector */ hasAgent(qualifiedName: string): boolean; /** * Get the state of a connector for a specific agent * * @param qualifiedName - Qualified name of the agent (e.g., "herdctl.security-auditor") * @returns The connector state, or undefined if not found */ getState(qualifiedName: string): ChatManagerConnectorState | undefined; /** * Handle an incoming Discord message * * This method: * 1. Gets or creates a session for the channel * 2. Builds job context from the message * 3. Executes the job via trigger * 4. Sends the response back to Discord * * @param qualifiedName - Qualified name of the agent handling the message * @param event - The Discord message event */ private handleMessage; /** * Handle errors from Discord connectors * * Logs errors without crashing the connector * * @param qualifiedName - Qualified name of the agent that encountered the error * @param error - The error that occurred */ private handleError; private getChannelKey; private stopChannelRun; private retryChannelRun; private toTextChannel; /** * Build a DiscordMessageEvent from scratch for programmatic triggers * (e.g. /retry). This keeps the boilerplate in one place so any new * fields on DiscordMessageEvent only need updating here. */ private createSyntheticMessageEvent; private getChannelRunInfo; private getChannelUsage; private accumulateUsage; private getAgentCumulativeUsage; private runChannelSkill; private runChannelPrompt; private discoverAgentSkills; private getAgentByQualifiedName; private getConfiguredDiscordSkills; private getAgentConfigSummary; /** Discord's maximum message length */ private static readonly MAX_MESSAGE_LENGTH; /** * Format an error message for Discord display * * Creates a user-friendly error message with guidance on how to proceed. * Returns an embed when agentName is provided, plain text otherwise. * * @param error - The error that occurred * @param agentName - Optional agent name for embed footer * @returns Formatted error message string or embed payload */ formatErrorMessage(error: Error, agentName?: string): string | DiscordReplyPayload; /** * Split a response into chunks that fit Discord's 2000 character limit * * Uses the shared splitMessage utility from @herdctl/chat. * * @param text - The text to split * @returns Array of text chunks, each under 2000 characters */ splitResponse(text: string): string[]; /** * Send a response to Discord, splitting if necessary * * @param reply - The reply function from the message event * @param content - The content to send */ sendResponse(reply: (content: string) => Promise, content: string): Promise; /** * Resolve the agent's working directory to an absolute path string */ private resolveWorkingDirectory; /** Maximum characters to inline for text/code file content */ private static readonly TEXT_INLINE_MAX_CHARS; /** * Check if a content type matches a MIME pattern (supports wildcards like "image/*") */ private static matchesMimePattern; /** * Process file attachments: download, categorize, and prepare prompt sections. * * - Text/code files are inlined directly into the prompt * - Images and PDFs are saved to disk so the agent can use its Read tool * * Returns prompt sections to prepend, paths of downloaded files for cleanup, * and a list of skipped files with reasons. */ private static processAttachments; /** * Clean up downloaded attachment files after processing */ private static cleanupAttachments; } //# sourceMappingURL=manager.d.ts.map