opensentinel 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/bot-KJ26BG56.js +15 -0
- package/dist/bot-KJ26BG56.js.map +1 -0
- package/dist/charts-MMXM6BWW.js +241 -0
- package/dist/charts-MMXM6BWW.js.map +1 -0
- package/dist/chunk-4LVWXUNC.js +1079 -0
- package/dist/chunk-4LVWXUNC.js.map +1 -0
- package/dist/chunk-4TG2IG5K.js +5249 -0
- package/dist/chunk-4TG2IG5K.js.map +1 -0
- package/dist/chunk-6DRDKB45.js +251 -0
- package/dist/chunk-6DRDKB45.js.map +1 -0
- package/dist/chunk-6SNHU3CY.js +123 -0
- package/dist/chunk-6SNHU3CY.js.map +1 -0
- package/dist/chunk-CI6Q63MM.js +1613 -0
- package/dist/chunk-CI6Q63MM.js.map +1 -0
- package/dist/chunk-CQ4JURG7.js +57 -0
- package/dist/chunk-CQ4JURG7.js.map +1 -0
- package/dist/chunk-F6QUZQGI.js +51 -0
- package/dist/chunk-F6QUZQGI.js.map +1 -0
- package/dist/chunk-GK3E2I7A.js +216 -0
- package/dist/chunk-GK3E2I7A.js.map +1 -0
- package/dist/chunk-GUBEEYDW.js +211 -0
- package/dist/chunk-GUBEEYDW.js.map +1 -0
- package/dist/chunk-GVJVEWHI.js +29 -0
- package/dist/chunk-GVJVEWHI.js.map +1 -0
- package/dist/chunk-HH2HBTQM.js +806 -0
- package/dist/chunk-HH2HBTQM.js.map +1 -0
- package/dist/chunk-JXUP2X7V.js +129 -0
- package/dist/chunk-JXUP2X7V.js.map +1 -0
- package/dist/chunk-KHNYJY2Z.js +178 -0
- package/dist/chunk-KHNYJY2Z.js.map +1 -0
- package/dist/chunk-L3F43VPB.js +652 -0
- package/dist/chunk-L3F43VPB.js.map +1 -0
- package/dist/chunk-L3PDU3XN.js +803 -0
- package/dist/chunk-L3PDU3XN.js.map +1 -0
- package/dist/chunk-NSBPE2FW.js +17 -0
- package/dist/chunk-NSBPE2FW.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/setup.d.ts +9 -0
- package/dist/commands/setup.js +374 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +8 -0
- package/dist/commands/start.js +27 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.js +57 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +8 -0
- package/dist/commands/stop.js +37 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/utils.d.ts +50 -0
- package/dist/commands/utils.js +36 -0
- package/dist/commands/utils.js.map +1 -0
- package/dist/discord-ZOJFTVTB.js +49 -0
- package/dist/discord-ZOJFTVTB.js.map +1 -0
- package/dist/imessage-JFRB6EJ7.js +14 -0
- package/dist/imessage-JFRB6EJ7.js.map +1 -0
- package/dist/lib.d.ts +855 -0
- package/dist/lib.js +274 -0
- package/dist/lib.js.map +1 -0
- package/dist/mcp-LS7Q3Z5W.js +30 -0
- package/dist/mcp-LS7Q3Z5W.js.map +1 -0
- package/dist/scheduler-EZ7CZMCS.js +42 -0
- package/dist/scheduler-EZ7CZMCS.js.map +1 -0
- package/dist/signal-T3MCSULM.js +14 -0
- package/dist/signal-T3MCSULM.js.map +1 -0
- package/dist/slack-N2M4FHAJ.js +54 -0
- package/dist/slack-N2M4FHAJ.js.map +1 -0
- package/dist/src-K7GASHRH.js +430 -0
- package/dist/src-K7GASHRH.js.map +1 -0
- package/dist/tools-24GZHYRF.js +16 -0
- package/dist/tools-24GZHYRF.js.map +1 -0
- package/dist/whatsapp-VCRUPAO5.js +14 -0
- package/dist/whatsapp-VCRUPAO5.js.map +1 -0
- package/drizzle/0000_chilly_shinobi_shaw.sql +75 -0
- package/drizzle/0001_freezing_shape.sql +274 -0
- package/drizzle/meta/0000_snapshot.json +529 -0
- package/drizzle/meta/0001_snapshot.json +2576 -0
- package/drizzle/meta/_journal.json +20 -0
- package/package.json +98 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/inputs/discord/index.ts","../src/inputs/discord/commands.ts"],"sourcesContent":["import {\n Client,\n GatewayIntentBits,\n Events,\n REST,\n Routes,\n Collection,\n type Message as DiscordMessage,\n type VoiceState as DiscordVoiceState,\n type GuildMember,\n type Interaction,\n ChannelType,\n AttachmentBuilder,\n EmbedBuilder,\n} from \"discord.js\";\nimport {\n joinVoiceChannel,\n createAudioPlayer,\n createAudioResource,\n AudioPlayerStatus,\n VoiceConnectionStatus,\n entersState,\n type VoiceConnection,\n type AudioPlayer,\n} from \"@discordjs/voice\";\nimport { Readable } from \"stream\";\nimport { chatWithTools, type Message } from \"../../core/brain\";\nimport { transcribeAudio } from \"../../outputs/stt\";\nimport { textToSpeech } from \"../../outputs/tts\";\nimport {\n slashCommands,\n getCommandData,\n getCommand,\n getSession,\n addToSession,\n splitMessage,\n} from \"./commands\";\n\n/**\n * Discord bot configuration\n */\nexport interface DiscordBotConfig {\n token: string;\n clientId: string;\n guildId?: string; // Optional: for development/testing with guild-specific commands\n allowedUserIds?: string[]; // Optional: restrict to specific users\n allowedRoleIds?: string[]; // Optional: restrict to users with specific roles\n allowDMs?: boolean; // Allow direct messages\n allowChannels?: boolean; // Allow server channels\n}\n\n/**\n * Voice connection state\n */\ninterface VoiceState {\n connection: VoiceConnection;\n player: AudioPlayer;\n guildId: string;\n channelId: string;\n}\n\n/**\n * Discord bot session data\n */\nexport interface DiscordSessionData {\n messages: Message[];\n lastActivity: Date;\n}\n\n/**\n * Discord bot class\n */\nexport class DiscordBot {\n private client: Client;\n private config: DiscordBotConfig;\n private rest: REST;\n private voiceConnections: Map<string, VoiceState> = new Map();\n private commandCollection: Collection<string, typeof slashCommands[number]>;\n private isReady: boolean = false;\n\n constructor(config: DiscordBotConfig) {\n this.config = config;\n\n // Note: MessageContent requires Privileged Gateway Intents\n // Enable at: https://discord.com/developers/applications/{APP_ID}/bot\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.GuildVoiceStates,\n GatewayIntentBits.MessageContent, // Privileged - must be enabled in Developer Portal\n // GatewayIntentBits.GuildMembers, // Optional - enable for role-based authorization\n ],\n });\n\n this.rest = new REST({ version: \"10\" }).setToken(config.token);\n\n // Set up command collection\n this.commandCollection = new Collection();\n for (const command of slashCommands) {\n this.commandCollection.set(command.data.name, command);\n }\n\n this.setupEventHandlers();\n }\n\n /**\n * Set up Discord event handlers\n */\n private setupEventHandlers(): void {\n // Bot ready event\n this.client.once(Events.ClientReady, (readyClient) => {\n this.isReady = true;\n console.log(`[Discord] Bot ready as ${readyClient.user.tag}`);\n console.log(\n `[Discord] Connected to ${readyClient.guilds.cache.size} guild(s)`\n );\n });\n\n // Slash command interaction handler\n this.client.on(Events.InteractionCreate, async (interaction) => {\n await this.handleInteraction(interaction);\n });\n\n // Message handler (for DMs and @mentions)\n this.client.on(Events.MessageCreate, async (message) => {\n await this.handleMessage(message);\n });\n\n // Voice state update handler\n this.client.on(Events.VoiceStateUpdate, async (oldState, newState) => {\n await this.handleVoiceStateUpdate(oldState as any, newState as any);\n });\n\n // Error handler\n this.client.on(Events.Error, (error) => {\n console.error(\"[Discord] Client error:\", error);\n });\n\n // Warn handler\n this.client.on(Events.Warn, (warning) => {\n console.warn(\"[Discord] Warning:\", warning);\n });\n }\n\n /**\n * Handle slash command interactions\n */\n private async handleInteraction(interaction: Interaction): Promise<void> {\n if (!interaction.isChatInputCommand()) return;\n\n // Check user authorization\n if (!this.isUserAuthorized(interaction.user.id, interaction.member as GuildMember | null)) {\n await interaction.reply({\n content: \"You are not authorized to use this bot.\",\n ephemeral: true,\n });\n return;\n }\n\n const command = this.commandCollection.get(interaction.commandName);\n if (!command) {\n console.warn(`[Discord] Unknown command: ${interaction.commandName}`);\n return;\n }\n\n // Handle voice commands specially\n if (interaction.commandName === \"voice\") {\n await this.handleVoiceCommand(interaction);\n return;\n }\n\n try {\n await command.execute(interaction);\n } catch (error) {\n console.error(\n `[Discord] Error executing command ${interaction.commandName}:`,\n error\n );\n const errorMessage = \"There was an error executing this command.\";\n if (interaction.replied || interaction.deferred) {\n await interaction.followUp({ content: errorMessage, ephemeral: true });\n } else {\n await interaction.reply({ content: errorMessage, ephemeral: true });\n }\n }\n }\n\n /**\n * Handle voice slash commands\n */\n private async handleVoiceCommand(\n interaction: Interaction\n ): Promise<void> {\n if (!interaction.isChatInputCommand()) return;\n\n const subcommand = interaction.options.getSubcommand();\n\n switch (subcommand) {\n case \"join\":\n await this.joinVoiceChannel(interaction);\n break;\n case \"leave\":\n await this.leaveVoiceChannel(interaction);\n break;\n case \"speak\":\n await this.speakInVoiceChannel(interaction);\n break;\n default:\n await interaction.reply({\n content: \"Unknown voice subcommand.\",\n ephemeral: true,\n });\n }\n }\n\n /**\n * Join a voice channel\n */\n private async joinVoiceChannel(\n interaction: Interaction\n ): Promise<void> {\n if (!interaction.isChatInputCommand() || !interaction.guild) {\n return;\n }\n\n const member = interaction.member as GuildMember;\n const voiceChannel = member.voice.channel;\n\n if (!voiceChannel) {\n await interaction.reply({\n content: \"You need to be in a voice channel for me to join.\",\n ephemeral: true,\n });\n return;\n }\n\n try {\n const connection = joinVoiceChannel({\n channelId: voiceChannel.id,\n guildId: interaction.guild.id,\n adapterCreator: interaction.guild.voiceAdapterCreator,\n });\n\n const player = createAudioPlayer();\n connection.subscribe(player);\n\n // Wait for connection to be ready\n await entersState(connection, VoiceConnectionStatus.Ready, 30_000);\n\n this.voiceConnections.set(interaction.guild.id, {\n connection,\n player,\n guildId: interaction.guild.id,\n channelId: voiceChannel.id,\n });\n\n await interaction.reply({\n content: `Joined ${voiceChannel.name}!`,\n ephemeral: true,\n });\n\n console.log(\n `[Discord] Joined voice channel: ${voiceChannel.name} in ${interaction.guild.name}`\n );\n } catch (error) {\n console.error(\"[Discord] Error joining voice channel:\", error);\n await interaction.reply({\n content: \"Failed to join the voice channel. Please try again.\",\n ephemeral: true,\n });\n }\n }\n\n /**\n * Leave a voice channel\n */\n private async leaveVoiceChannel(\n interaction: Interaction\n ): Promise<void> {\n if (!interaction.isChatInputCommand() || !interaction.guild) {\n return;\n }\n\n const voiceState = this.voiceConnections.get(interaction.guild.id);\n\n if (!voiceState) {\n await interaction.reply({\n content: \"I'm not in a voice channel.\",\n ephemeral: true,\n });\n return;\n }\n\n try {\n voiceState.player.stop();\n voiceState.connection.destroy();\n this.voiceConnections.delete(interaction.guild.id);\n\n await interaction.reply({\n content: \"Left the voice channel.\",\n ephemeral: true,\n });\n\n console.log(\n `[Discord] Left voice channel in ${interaction.guild.name}`\n );\n } catch (error) {\n console.error(\"[Discord] Error leaving voice channel:\", error);\n await interaction.reply({\n content: \"Failed to leave the voice channel.\",\n ephemeral: true,\n });\n }\n }\n\n /**\n * Speak text in a voice channel using TTS\n */\n private async speakInVoiceChannel(\n interaction: Interaction\n ): Promise<void> {\n if (!interaction.isChatInputCommand() || !interaction.guild) {\n return;\n }\n\n const voiceState = this.voiceConnections.get(interaction.guild.id);\n\n if (!voiceState) {\n await interaction.reply({\n content: \"I need to be in a voice channel first. Use `/voice join`.\",\n ephemeral: true,\n });\n return;\n }\n\n const text = interaction.options.getString(\"text\", true);\n\n await interaction.deferReply({ ephemeral: true });\n\n try {\n const audioBuffer = await textToSpeech(text);\n\n if (!audioBuffer) {\n await interaction.editReply(\"Failed to generate speech. TTS service may be unavailable.\");\n return;\n }\n\n // Create readable stream from buffer\n const stream = Readable.from(audioBuffer);\n const resource = createAudioResource(stream);\n\n voiceState.player.play(resource);\n\n // Wait for playback to finish\n await new Promise<void>((resolve) => {\n voiceState.player.once(AudioPlayerStatus.Idle, () => resolve());\n });\n\n await interaction.editReply(`Spoke: \"${text}\"`);\n\n console.log(\n `[Discord] Spoke in voice channel: \"${text.substring(0, 50)}...\"`\n );\n } catch (error) {\n console.error(\"[Discord] Error speaking in voice channel:\", error);\n await interaction.editReply(\n \"Failed to speak in the voice channel. Please try again.\"\n );\n }\n }\n\n /**\n * Handle incoming messages (DMs and @mentions)\n */\n private async handleMessage(message: DiscordMessage): Promise<void> {\n // Ignore bot messages\n if (message.author.bot) return;\n\n // Check if it's a DM or a mention\n const isDM = message.channel.type === ChannelType.DM;\n const isMentioned = message.mentions.has(this.client.user!.id);\n\n // Skip if not DM and not mentioned\n if (!isDM && !isMentioned) return;\n\n // Check configuration\n if (isDM && !this.config.allowDMs) return;\n if (!isDM && !this.config.allowChannels) return;\n\n // Check authorization\n if (!this.isUserAuthorized(message.author.id, message.member)) return;\n\n // Get the actual content (remove mention if present)\n let content = message.content;\n if (isMentioned) {\n content = content.replace(/<@!?\\d+>/g, \"\").trim();\n }\n\n if (!content && message.attachments.size === 0) return;\n\n const userId = message.author.id;\n\n try {\n // Show typing indicator\n if (\"sendTyping\" in message.channel) {\n await (message.channel as any).sendTyping();\n }\n\n // Handle file attachments\n let processedContent = content;\n if (message.attachments.size > 0) {\n const attachmentDescriptions = await this.processAttachments(message);\n if (attachmentDescriptions.length > 0) {\n processedContent += \"\\n\\n[Attachments:\\n\" + attachmentDescriptions.join(\"\\n\") + \"]\";\n }\n }\n\n addToSession(userId, { role: \"user\", content: processedContent });\n\n const response = await chatWithTools(\n getSession(userId),\n `discord:${userId}`,\n async () => {\n // Keep typing indicator alive during tool use\n if (\"sendTyping\" in message.channel) {\n await (message.channel as any).sendTyping();\n }\n }\n );\n\n addToSession(userId, { role: \"assistant\", content: response.content });\n\n // Build response with tool usage info\n let finalResponse = response.content;\n if (response.toolsUsed && response.toolsUsed.length > 0) {\n const toolList = [...new Set(response.toolsUsed)].join(\", \");\n finalResponse = `*Used: ${toolList}*\\n\\n${response.content}`;\n }\n\n // Send response (handle Discord's 2000 char limit)\n if (finalResponse.length > 2000) {\n const chunks = splitMessage(finalResponse, 2000);\n for (const chunk of chunks) {\n await message.reply(chunk);\n }\n } else {\n await message.reply(finalResponse);\n }\n\n console.log(\n `[Discord] Processed message from ${message.author.tag}. Tokens: ${response.inputTokens}/${response.outputTokens}` +\n (response.toolsUsed ? ` Tools: ${response.toolsUsed.join(\", \")}` : \"\")\n );\n } catch (error) {\n console.error(\"[Discord] Error processing message:\", error);\n await message.reply(\n \"Sorry, I encountered an error processing your message. Please try again.\"\n );\n }\n }\n\n /**\n * Process message attachments\n */\n private async processAttachments(\n message: DiscordMessage\n ): Promise<string[]> {\n const descriptions: string[] = [];\n\n for (const [, attachment] of message.attachments) {\n const contentType = attachment.contentType || \"\";\n const fileName = attachment.name || \"unknown\";\n\n if (contentType.startsWith(\"audio/\")) {\n // Handle voice/audio messages\n try {\n const response = await fetch(attachment.url);\n const audioBuffer = await response.arrayBuffer();\n const transcription = await transcribeAudio(Buffer.from(audioBuffer));\n\n if (transcription) {\n descriptions.push(`Audio transcription (${fileName}): \"${transcription}\"`);\n } else {\n descriptions.push(`Audio file: ${fileName} (could not transcribe)`);\n }\n } catch (error) {\n console.error(\"[Discord] Error processing audio attachment:\", error);\n descriptions.push(`Audio file: ${fileName} (error processing)`);\n }\n } else if (contentType.startsWith(\"text/\")) {\n // Handle text files\n try {\n const response = await fetch(attachment.url);\n const text = await response.text();\n const preview = text.length > 1000 ? text.substring(0, 1000) + \"...\" : text;\n descriptions.push(`Text file (${fileName}):\\n${preview}`);\n } catch (error) {\n descriptions.push(`Text file: ${fileName} (could not read)`);\n }\n } else {\n // Other file types\n descriptions.push(\n `File: ${fileName} (${contentType || \"unknown type\"}, ${\n attachment.size\n } bytes)`\n );\n }\n }\n\n return descriptions;\n }\n\n /**\n * Handle voice state updates\n */\n private async handleVoiceStateUpdate(\n oldState: any,\n newState: any\n ): Promise<void> {\n // Check if the bot was disconnected\n if (\n oldState.member?.id === this.client.user?.id &&\n !newState.channelId &&\n oldState.channelId\n ) {\n // Bot was disconnected from voice\n const guildId = oldState.guild?.id || oldState.guildId;\n const voiceState = this.voiceConnections.get(guildId);\n\n if (voiceState) {\n voiceState.player.stop();\n this.voiceConnections.delete(guildId);\n console.log(`[Discord] Bot disconnected from voice in ${oldState.guild?.name || guildId}`);\n }\n }\n }\n\n /**\n * Check if a user is authorized to use the bot\n */\n private isUserAuthorized(\n userId: string,\n member: GuildMember | null\n ): boolean {\n // If no restrictions, allow everyone\n if (\n !this.config.allowedUserIds?.length &&\n !this.config.allowedRoleIds?.length\n ) {\n return true;\n }\n\n // Check user ID allowlist (primary authorization method)\n if (this.config.allowedUserIds?.includes(userId)) {\n return true;\n }\n\n // Check role allowlist (requires GuildMembers intent to be enabled)\n // Note: Role checks may fail silently if GuildMembers intent is not enabled\n if (member && this.config.allowedRoleIds?.length) {\n try {\n for (const roleId of this.config.allowedRoleIds) {\n if (member.roles?.cache?.has(roleId)) {\n return true;\n }\n }\n } catch {\n // Role cache not available - GuildMembers intent not enabled\n }\n }\n\n return false;\n }\n\n /**\n * Register slash commands with Discord\n */\n async registerCommands(): Promise<void> {\n const commands = getCommandData();\n\n try {\n console.log(\"[Discord] Registering slash commands...\");\n\n if (this.config.guildId) {\n // Register guild-specific commands (instant update, good for testing)\n await this.rest.put(\n Routes.applicationGuildCommands(\n this.config.clientId,\n this.config.guildId\n ),\n { body: commands }\n );\n console.log(\n `[Discord] Registered ${commands.length} guild commands for guild ${this.config.guildId}`\n );\n } else {\n // Register global commands (can take up to 1 hour to propagate)\n await this.rest.put(Routes.applicationCommands(this.config.clientId), {\n body: commands,\n });\n console.log(\n `[Discord] Registered ${commands.length} global commands`\n );\n }\n } catch (error) {\n console.error(\"[Discord] Error registering commands:\", error);\n throw error;\n }\n }\n\n /**\n * Start the Discord bot\n */\n async start(): Promise<void> {\n console.log(\"[Discord] Starting bot...\");\n\n // Register commands first\n await this.registerCommands();\n\n // Login to Discord\n await this.client.login(this.config.token);\n }\n\n /**\n * Stop the Discord bot\n */\n async stop(): Promise<void> {\n console.log(\"[Discord] Stopping bot...\");\n\n // Disconnect all voice connections\n for (const [guildId, voiceState] of this.voiceConnections) {\n voiceState.player.stop();\n voiceState.connection.destroy();\n this.voiceConnections.delete(guildId);\n }\n\n // Destroy client\n this.client.destroy();\n this.isReady = false;\n\n console.log(\"[Discord] Bot stopped\");\n }\n\n /**\n * Get the Discord client\n */\n getClient(): Client {\n return this.client;\n }\n\n /**\n * Check if bot is ready\n */\n ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Send a message to a channel\n */\n async sendMessage(channelId: string, content: string): Promise<void> {\n const channel = await this.client.channels.fetch(channelId);\n if (channel?.isTextBased() && \"send\" in channel) {\n await channel.send(content);\n }\n }\n\n /**\n * Send a message with an embed\n */\n async sendEmbed(\n channelId: string,\n title: string,\n description: string,\n color?: number\n ): Promise<void> {\n const channel = await this.client.channels.fetch(channelId);\n if (channel?.isTextBased() && \"send\" in channel) {\n const embed = new EmbedBuilder()\n .setTitle(title)\n .setDescription(description)\n .setColor(color || 0x5865f2)\n .setTimestamp();\n\n await channel.send({ embeds: [embed] });\n }\n }\n\n /**\n * Send a file to a channel\n */\n async sendFile(\n channelId: string,\n buffer: Buffer,\n filename: string,\n content?: string\n ): Promise<void> {\n const channel = await this.client.channels.fetch(channelId);\n if (channel?.isTextBased() && \"send\" in channel) {\n const attachment = new AttachmentBuilder(buffer, { name: filename });\n await channel.send({\n content,\n files: [attachment],\n });\n }\n }\n}\n\n/**\n * Create and configure Discord bot\n */\nexport function createDiscordBot(config: DiscordBotConfig): DiscordBot {\n return new DiscordBot(config);\n}\n\n/**\n * Export commands module\n */\nexport * from \"./commands\";\n\n/**\n * Default export\n */\nexport default {\n createDiscordBot,\n DiscordBot,\n slashCommands,\n getCommandData,\n getCommand,\n};\n","import {\n SlashCommandBuilder,\n type ChatInputCommandInteraction,\n type RESTPostAPIChatInputApplicationCommandsJSONBody,\n} from \"discord.js\";\nimport { chatWithTools, type Message } from \"../../core/brain\";\nimport { scheduleReminder } from \"../../core/scheduler\";\n\n/**\n * Discord slash command definitions\n */\nexport interface SlashCommand {\n data: RESTPostAPIChatInputApplicationCommandsJSONBody;\n execute: (interaction: ChatInputCommandInteraction) => Promise<void>;\n}\n\n// Session storage for conversation history\nconst sessions = new Map<string, Message[]>();\nconst MAX_HISTORY = 20;\n\nfunction getSession(userId: string): Message[] {\n if (!sessions.has(userId)) {\n sessions.set(userId, []);\n }\n return sessions.get(userId)!;\n}\n\nfunction addToSession(userId: string, message: Message): void {\n const session = getSession(userId);\n session.push(message);\n if (session.length > MAX_HISTORY) {\n sessions.set(userId, session.slice(-MAX_HISTORY));\n }\n}\n\nfunction clearSession(userId: string): void {\n sessions.set(userId, []);\n}\n\n/**\n * /ask - Ask OpenSentinel a question\n */\nexport const askCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"ask\")\n .setDescription(\"Ask OpenSentinel a question\")\n .addStringOption((option) =>\n option\n .setName(\"question\")\n .setDescription(\"Your question for OpenSentinel\")\n .setRequired(true)\n )\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n const question = interaction.options.getString(\"question\", true);\n const userId = interaction.user.id;\n\n await interaction.deferReply();\n\n try {\n addToSession(userId, { role: \"user\", content: question });\n\n const response = await chatWithTools(\n getSession(userId),\n `discord:${userId}`\n );\n\n addToSession(userId, { role: \"assistant\", content: response.content });\n\n // Build response with tool usage info\n let finalResponse = response.content;\n if (response.toolsUsed && response.toolsUsed.length > 0) {\n const toolList = [...new Set(response.toolsUsed)].join(\", \");\n finalResponse = `*Used: ${toolList}*\\n\\n${response.content}`;\n }\n\n // Discord has a 2000 character limit\n if (finalResponse.length > 2000) {\n const chunks = splitMessage(finalResponse, 2000);\n await interaction.editReply(chunks[0]);\n for (let i = 1; i < chunks.length; i++) {\n await interaction.followUp(chunks[i]);\n }\n } else {\n await interaction.editReply(finalResponse);\n }\n\n console.log(\n `[Discord] Processed /ask from ${interaction.user.tag}. Tokens: ${response.inputTokens}/${response.outputTokens}`\n );\n } catch (error) {\n console.error(\"[Discord] Error processing /ask:\", error);\n await interaction.editReply(\n \"Sorry, I encountered an error processing your question. Please try again.\"\n );\n }\n },\n};\n\n/**\n * /chat - Multi-turn conversation with OpenSentinel\n */\nexport const chatCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"chat\")\n .setDescription(\"Have a conversation with OpenSentinel\")\n .addStringOption((option) =>\n option\n .setName(\"message\")\n .setDescription(\"Your message\")\n .setRequired(true)\n )\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n const message = interaction.options.getString(\"message\", true);\n const userId = interaction.user.id;\n\n await interaction.deferReply();\n\n try {\n addToSession(userId, { role: \"user\", content: message });\n\n const response = await chatWithTools(\n getSession(userId),\n `discord:${userId}`\n );\n\n addToSession(userId, { role: \"assistant\", content: response.content });\n\n let finalResponse = response.content;\n if (response.toolsUsed && response.toolsUsed.length > 0) {\n const toolList = [...new Set(response.toolsUsed)].join(\", \");\n finalResponse = `*Used: ${toolList}*\\n\\n${response.content}`;\n }\n\n if (finalResponse.length > 2000) {\n const chunks = splitMessage(finalResponse, 2000);\n await interaction.editReply(chunks[0]);\n for (let i = 1; i < chunks.length; i++) {\n await interaction.followUp(chunks[i]);\n }\n } else {\n await interaction.editReply(finalResponse);\n }\n\n console.log(\n `[Discord] Processed /chat from ${interaction.user.tag}. Tokens: ${response.inputTokens}/${response.outputTokens}`\n );\n } catch (error) {\n console.error(\"[Discord] Error processing /chat:\", error);\n await interaction.editReply(\n \"Sorry, I encountered an error processing your message. Please try again.\"\n );\n }\n },\n};\n\n/**\n * /clear - Clear conversation history\n */\nexport const clearCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"clear\")\n .setDescription(\"Clear your conversation history with OpenSentinel\")\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n clearSession(interaction.user.id);\n await interaction.reply({\n content: \"Conversation history cleared.\",\n ephemeral: true,\n });\n console.log(`[Discord] Cleared history for ${interaction.user.tag}`);\n },\n};\n\n/**\n * /remind - Set a reminder\n */\nexport const remindCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"remind\")\n .setDescription(\"Set a reminder\")\n .addIntegerOption((option) =>\n option\n .setName(\"time\")\n .setDescription(\"Time amount\")\n .setRequired(true)\n .setMinValue(1)\n )\n .addStringOption((option) =>\n option\n .setName(\"unit\")\n .setDescription(\"Time unit\")\n .setRequired(true)\n .addChoices(\n { name: \"seconds\", value: \"s\" },\n { name: \"minutes\", value: \"m\" },\n { name: \"hours\", value: \"h\" }\n )\n )\n .addStringOption((option) =>\n option\n .setName(\"message\")\n .setDescription(\"Reminder message\")\n .setRequired(true)\n )\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n const time = interaction.options.getInteger(\"time\", true);\n const unit = interaction.options.getString(\"unit\", true);\n const message = interaction.options.getString(\"message\", true);\n\n const multipliers: Record<string, number> = {\n s: 1000,\n m: 60 * 1000,\n h: 60 * 60 * 1000,\n };\n const delayMs = time * multipliers[unit];\n\n try {\n await scheduleReminder(\n message,\n delayMs,\n `discord:${interaction.channelId}:${interaction.user.id}`\n );\n\n const timeStr =\n unit === \"s\" ? \"seconds\" : unit === \"m\" ? \"minutes\" : \"hours\";\n await interaction.reply({\n content: `Reminder set for ${time} ${timeStr}: \"${message}\"`,\n ephemeral: true,\n });\n\n console.log(\n `[Discord] Reminder set by ${interaction.user.tag}: ${time}${unit} - \"${message}\"`\n );\n } catch (error) {\n console.error(\"[Discord] Error setting reminder:\", error);\n await interaction.reply({\n content: \"Sorry, I couldn't set the reminder. Please try again.\",\n ephemeral: true,\n });\n }\n },\n};\n\n/**\n * /status - Check OpenSentinel status\n */\nexport const statusCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"status\")\n .setDescription(\"Check OpenSentinel status and capabilities\")\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n const session = getSession(interaction.user.id);\n const historyCount = session.length;\n\n await interaction.reply({\n content: `**OpenSentinel Status**\n\nBot: Online\nYour conversation history: ${historyCount} messages\n\n**Capabilities:**\n- Chat and answer questions using Claude AI\n- Execute shell commands\n- Read and write files\n- Search the web\n- Remember important information\n- Set reminders\n- Voice channel support (join, speak)\n\nUse \\`/help\\` for available commands.`,\n ephemeral: true,\n });\n },\n};\n\n/**\n * /help - Show available commands\n */\nexport const helpCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"help\")\n .setDescription(\"Show available OpenSentinel commands\")\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n await interaction.reply({\n content: `**OpenSentinel Commands**\n\n\\`/ask <question>\\` - Ask a single question\n\\`/chat <message>\\` - Continue a conversation\n\\`/clear\\` - Clear your conversation history\n\\`/remind <time> <unit> <message>\\` - Set a reminder\n\\`/status\\` - Check bot status\n\\`/voice join\\` - Join your voice channel\n\\`/voice leave\\` - Leave the voice channel\n\\`/voice speak <text>\\` - Speak text in voice channel\n\\`/help\\` - Show this help message\n\n**Tips:**\n- Use \\`/chat\\` for multi-turn conversations with context\n- Use \\`/ask\\` for quick one-off questions\n- DM me directly to chat without slash commands`,\n ephemeral: true,\n });\n },\n};\n\n/**\n * /voice - Voice channel operations\n */\nexport const voiceCommand: SlashCommand = {\n data: new SlashCommandBuilder()\n .setName(\"voice\")\n .setDescription(\"Voice channel operations\")\n .addSubcommand((subcommand) =>\n subcommand.setName(\"join\").setDescription(\"Join your current voice channel\")\n )\n .addSubcommand((subcommand) =>\n subcommand.setName(\"leave\").setDescription(\"Leave the voice channel\")\n )\n .addSubcommand((subcommand) =>\n subcommand\n .setName(\"speak\")\n .setDescription(\"Speak text in the voice channel\")\n .addStringOption((option) =>\n option\n .setName(\"text\")\n .setDescription(\"Text to speak\")\n .setRequired(true)\n )\n )\n .toJSON(),\n\n async execute(interaction: ChatInputCommandInteraction): Promise<void> {\n const subcommand = interaction.options.getSubcommand();\n\n // These will be implemented in the main Discord bot file\n // This is a placeholder that emits events for the bot to handle\n await interaction.reply({\n content: `Voice command received: ${subcommand}. Voice handling is managed by the Discord bot.`,\n ephemeral: true,\n });\n },\n};\n\n/**\n * All available slash commands\n */\nexport const slashCommands: SlashCommand[] = [\n askCommand,\n chatCommand,\n clearCommand,\n remindCommand,\n statusCommand,\n helpCommand,\n voiceCommand,\n];\n\n/**\n * Get command data for registration\n */\nexport function getCommandData(): RESTPostAPIChatInputApplicationCommandsJSONBody[] {\n return slashCommands.map((cmd) => cmd.data);\n}\n\n/**\n * Get command by name\n */\nexport function getCommand(name: string): SlashCommand | undefined {\n return slashCommands.find(\n (cmd) => cmd.data.name === name\n );\n}\n\n/**\n * Session management exports for external use\n */\nexport {\n getSession,\n addToSession,\n clearSession,\n sessions,\n};\n\n/**\n * Helper function to split long messages\n */\nfunction splitMessage(text: string, maxLength: number): string[] {\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n\n // Find a good break point (newline or space)\n let breakPoint = remaining.lastIndexOf(\"\\n\", maxLength);\n if (breakPoint === -1 || breakPoint < maxLength / 2) {\n breakPoint = remaining.lastIndexOf(\" \", maxLength);\n }\n if (breakPoint === -1 || breakPoint < maxLength / 2) {\n breakPoint = maxLength;\n }\n\n chunks.push(remaining.slice(0, breakPoint));\n remaining = remaining.slice(breakPoint).trim();\n }\n\n return chunks;\n}\n\nexport { splitMessage };\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chatWithTools
|
|
3
|
+
} from "./chunk-CI6Q63MM.js";
|
|
4
|
+
|
|
5
|
+
// src/inputs/signal/index.ts
|
|
6
|
+
import { spawn } from "child_process";
|
|
7
|
+
var SignalBot = class {
|
|
8
|
+
config;
|
|
9
|
+
process = null;
|
|
10
|
+
conversations = /* @__PURE__ */ new Map();
|
|
11
|
+
isRunning = false;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = {
|
|
14
|
+
signalCliPath: config.signalCliPath || "signal-cli",
|
|
15
|
+
configDir: config.configDir || "~/.local/share/signal-cli",
|
|
16
|
+
allowedNumbers: config.allowedNumbers || [],
|
|
17
|
+
...config
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
async start() {
|
|
21
|
+
if (this.isRunning) return;
|
|
22
|
+
console.log(`[Signal] Starting signal-cli for ${this.config.phoneNumber}...`);
|
|
23
|
+
this.process = spawn(
|
|
24
|
+
this.config.signalCliPath,
|
|
25
|
+
["-u", this.config.phoneNumber, "jsonRpc"],
|
|
26
|
+
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
27
|
+
);
|
|
28
|
+
this.isRunning = true;
|
|
29
|
+
this.readMessages();
|
|
30
|
+
this.readStderr();
|
|
31
|
+
console.log("[Signal] Bot started, listening for messages...");
|
|
32
|
+
}
|
|
33
|
+
readMessages() {
|
|
34
|
+
if (!this.process?.stdout) return;
|
|
35
|
+
let buffer = "";
|
|
36
|
+
this.process.stdout.on("data", async (chunk) => {
|
|
37
|
+
buffer += chunk.toString();
|
|
38
|
+
const lines = buffer.split("\n");
|
|
39
|
+
buffer = lines.pop() || "";
|
|
40
|
+
for (const line of lines) {
|
|
41
|
+
if (!line.trim()) continue;
|
|
42
|
+
try {
|
|
43
|
+
const data = JSON.parse(line);
|
|
44
|
+
if (data.method === "receive") {
|
|
45
|
+
await this.handleMessage(data.params);
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
this.process.stdout.on("error", (error) => {
|
|
52
|
+
if (this.isRunning) {
|
|
53
|
+
console.error("[Signal] Error reading messages:", error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
readStderr() {
|
|
58
|
+
if (!this.process?.stderr) return;
|
|
59
|
+
this.process.stderr.on("data", (chunk) => {
|
|
60
|
+
const text = chunk.toString();
|
|
61
|
+
if (text.trim()) {
|
|
62
|
+
console.log(`[Signal] stderr: ${text.trim()}`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async handleMessage(message) {
|
|
67
|
+
const { envelope } = message;
|
|
68
|
+
if (!envelope.dataMessage?.message) return;
|
|
69
|
+
const sender = envelope.sourceNumber || envelope.source;
|
|
70
|
+
const text = envelope.dataMessage.message;
|
|
71
|
+
if (this.config.allowedNumbers && this.config.allowedNumbers.length > 0 && !this.config.allowedNumbers.includes(sender)) {
|
|
72
|
+
console.log(`[Signal] Ignoring message from unauthorized number: ${sender}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log(`[Signal] Message from ${sender}: ${text.slice(0, 50)}...`);
|
|
76
|
+
let context = this.conversations.get(sender);
|
|
77
|
+
if (!context) {
|
|
78
|
+
context = { messages: [], lastActivity: /* @__PURE__ */ new Date() };
|
|
79
|
+
this.conversations.set(sender, context);
|
|
80
|
+
}
|
|
81
|
+
context.messages.push({ role: "user", content: text });
|
|
82
|
+
context.lastActivity = /* @__PURE__ */ new Date();
|
|
83
|
+
if (context.messages.length > 10) {
|
|
84
|
+
context.messages = context.messages.slice(-10);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const response = await chatWithTools(context.messages, sender);
|
|
88
|
+
context.messages.push({ role: "assistant", content: response.content });
|
|
89
|
+
await this.sendMessage(sender, response.content);
|
|
90
|
+
console.log(`[Signal] Replied to ${sender}`);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error("[Signal] Error processing message:", error);
|
|
93
|
+
await this.sendMessage(sender, "Sorry, I encountered an error processing your request.");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async sendMessage(to, text) {
|
|
97
|
+
if (!this.process?.stdin) {
|
|
98
|
+
throw new Error("Signal not connected");
|
|
99
|
+
}
|
|
100
|
+
const request = {
|
|
101
|
+
jsonrpc: "2.0",
|
|
102
|
+
id: Date.now(),
|
|
103
|
+
method: "send",
|
|
104
|
+
params: {
|
|
105
|
+
recipient: [to],
|
|
106
|
+
message: text
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
this.process.stdin.write(JSON.stringify(request) + "\n");
|
|
110
|
+
}
|
|
111
|
+
async stop() {
|
|
112
|
+
this.isRunning = false;
|
|
113
|
+
if (this.process) {
|
|
114
|
+
this.process.kill();
|
|
115
|
+
this.process = null;
|
|
116
|
+
console.log("[Signal] Disconnected");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
get running() {
|
|
120
|
+
return this.isRunning;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var signal_default = SignalBot;
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
SignalBot,
|
|
127
|
+
signal_default
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=chunk-JXUP2X7V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/inputs/signal/index.ts"],"sourcesContent":["/**\n * Signal Integration using signal-cli\n * Connects OpenSentinel to Signal Messenger\n *\n * Prerequisites:\n * 1. Install signal-cli: https://github.com/AsamK/signal-cli\n * 2. Register/link your phone number with signal-cli\n * 3. Run signal-cli in JSON-RPC mode: signal-cli -u +1234567890 jsonRpc\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { chatWithTools } from \"../../core/brain\";\nimport type { Message } from \"../../core/brain\";\n\ninterface SignalConfig {\n phoneNumber: string;\n signalCliPath?: string;\n allowedNumbers?: string[];\n configDir?: string;\n}\n\ninterface SignalMessage {\n envelope: {\n source: string;\n sourceNumber: string;\n timestamp: number;\n dataMessage?: {\n message: string;\n timestamp: number;\n };\n };\n}\n\ninterface ConversationContext {\n messages: Message[];\n lastActivity: Date;\n}\n\nexport class SignalBot {\n private config: SignalConfig;\n private process: ChildProcess | null = null;\n private conversations: Map<string, ConversationContext> = new Map();\n private isRunning = false;\n\n constructor(config: SignalConfig) {\n this.config = {\n signalCliPath: config.signalCliPath || \"signal-cli\",\n configDir: config.configDir || \"~/.local/share/signal-cli\",\n allowedNumbers: config.allowedNumbers || [],\n ...config,\n };\n }\n\n async start(): Promise<void> {\n if (this.isRunning) return;\n\n console.log(`[Signal] Starting signal-cli for ${this.config.phoneNumber}...`);\n\n // Start signal-cli in JSON-RPC mode\n this.process = spawn(\n this.config.signalCliPath!,\n [\"-u\", this.config.phoneNumber, \"jsonRpc\"],\n { stdio: [\"pipe\", \"pipe\", \"pipe\"] }\n );\n\n this.isRunning = true;\n\n // Read stdout for incoming messages\n this.readMessages();\n\n // Read stderr for logging\n this.readStderr();\n\n console.log(\"[Signal] Bot started, listening for messages...\");\n }\n\n private readMessages(): void {\n if (!this.process?.stdout) return;\n\n let buffer = \"\";\n\n this.process.stdout.on(\"data\", async (chunk: Buffer) => {\n buffer += chunk.toString();\n\n // Process complete JSON lines\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const data = JSON.parse(line);\n if (data.method === \"receive\") {\n await this.handleMessage(data.params);\n }\n } catch {\n // Not valid JSON, skip\n }\n }\n });\n\n this.process.stdout.on(\"error\", (error) => {\n if (this.isRunning) {\n console.error(\"[Signal] Error reading messages:\", error);\n }\n });\n }\n\n private readStderr(): void {\n if (!this.process?.stderr) return;\n\n this.process.stderr.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n if (text.trim()) {\n console.log(`[Signal] stderr: ${text.trim()}`);\n }\n });\n }\n\n private async handleMessage(message: SignalMessage): Promise<void> {\n const { envelope } = message;\n if (!envelope.dataMessage?.message) return;\n\n const sender = envelope.sourceNumber || envelope.source;\n const text = envelope.dataMessage.message;\n\n // Check if sender is allowed\n if (\n this.config.allowedNumbers &&\n this.config.allowedNumbers.length > 0 &&\n !this.config.allowedNumbers.includes(sender)\n ) {\n console.log(`[Signal] Ignoring message from unauthorized number: ${sender}`);\n return;\n }\n\n console.log(`[Signal] Message from ${sender}: ${text.slice(0, 50)}...`);\n\n // Get or create conversation context\n let context = this.conversations.get(sender);\n if (!context) {\n context = { messages: [], lastActivity: new Date() };\n this.conversations.set(sender, context);\n }\n\n // Add user message to context\n context.messages.push({ role: \"user\", content: text });\n context.lastActivity = new Date();\n\n // Keep only last 10 messages\n if (context.messages.length > 10) {\n context.messages = context.messages.slice(-10);\n }\n\n try {\n // Get AI response\n const response = await chatWithTools(context.messages, sender);\n\n // Add assistant response to context\n context.messages.push({ role: \"assistant\", content: response.content });\n\n // Send response\n await this.sendMessage(sender, response.content);\n\n console.log(`[Signal] Replied to ${sender}`);\n } catch (error) {\n console.error(\"[Signal] Error processing message:\", error);\n await this.sendMessage(sender, \"Sorry, I encountered an error processing your request.\");\n }\n }\n\n async sendMessage(to: string, text: string): Promise<void> {\n if (!this.process?.stdin) {\n throw new Error(\"Signal not connected\");\n }\n\n const request = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method: \"send\",\n params: {\n recipient: [to],\n message: text,\n },\n };\n\n this.process.stdin.write(JSON.stringify(request) + \"\\n\");\n }\n\n async stop(): Promise<void> {\n this.isRunning = false;\n\n if (this.process) {\n this.process.kill();\n this.process = null;\n console.log(\"[Signal] Disconnected\");\n }\n }\n\n get running(): boolean {\n return this.isRunning;\n }\n}\n\nexport default SignalBot;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chat,
|
|
3
|
+
chatWithTools,
|
|
4
|
+
searchMemories,
|
|
5
|
+
storeMemory
|
|
6
|
+
} from "./chunk-CI6Q63MM.js";
|
|
7
|
+
import {
|
|
8
|
+
conversations,
|
|
9
|
+
db,
|
|
10
|
+
memories,
|
|
11
|
+
messages
|
|
12
|
+
} from "./chunk-4TG2IG5K.js";
|
|
13
|
+
import {
|
|
14
|
+
__require
|
|
15
|
+
} from "./chunk-NSBPE2FW.js";
|
|
16
|
+
|
|
17
|
+
// src/inputs/api/server.ts
|
|
18
|
+
import { Hono } from "hono";
|
|
19
|
+
import { cors } from "hono/cors";
|
|
20
|
+
import { logger } from "hono/logger";
|
|
21
|
+
import { desc, eq } from "drizzle-orm";
|
|
22
|
+
var serveStatic;
|
|
23
|
+
try {
|
|
24
|
+
serveStatic = __require("hono/bun").serveStatic;
|
|
25
|
+
} catch {
|
|
26
|
+
serveStatic = () => async (_c, next) => next();
|
|
27
|
+
}
|
|
28
|
+
var app = new Hono();
|
|
29
|
+
app.use("*", logger());
|
|
30
|
+
app.use("/api/*", cors());
|
|
31
|
+
app.get("/health", (c) => {
|
|
32
|
+
return c.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
33
|
+
});
|
|
34
|
+
app.post("/api/chat", async (c) => {
|
|
35
|
+
try {
|
|
36
|
+
const body = await c.req.json();
|
|
37
|
+
if (!body.messages || !Array.isArray(body.messages)) {
|
|
38
|
+
return c.json({ error: "messages array is required" }, 400);
|
|
39
|
+
}
|
|
40
|
+
const response = await chat(body.messages, body.systemPrompt);
|
|
41
|
+
return c.json({
|
|
42
|
+
content: response.content,
|
|
43
|
+
usage: {
|
|
44
|
+
inputTokens: response.inputTokens,
|
|
45
|
+
outputTokens: response.outputTokens
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("Chat API error:", error);
|
|
50
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
app.post("/api/chat/tools", async (c) => {
|
|
54
|
+
try {
|
|
55
|
+
const body = await c.req.json();
|
|
56
|
+
if (!body.messages || !Array.isArray(body.messages)) {
|
|
57
|
+
return c.json({ error: "messages array is required" }, 400);
|
|
58
|
+
}
|
|
59
|
+
const toolsUsed = [];
|
|
60
|
+
const response = await chatWithTools(body.messages, body.userId, (tool) => {
|
|
61
|
+
toolsUsed.push(tool);
|
|
62
|
+
});
|
|
63
|
+
return c.json({
|
|
64
|
+
content: response.content,
|
|
65
|
+
toolsUsed,
|
|
66
|
+
usage: {
|
|
67
|
+
inputTokens: response.inputTokens,
|
|
68
|
+
outputTokens: response.outputTokens
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error("Chat with tools API error:", error);
|
|
73
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
app.post("/api/ask", async (c) => {
|
|
77
|
+
try {
|
|
78
|
+
const body = await c.req.json();
|
|
79
|
+
if (!body.message) {
|
|
80
|
+
return c.json({ error: "message is required" }, 400);
|
|
81
|
+
}
|
|
82
|
+
const messages2 = [{ role: "user", content: body.message }];
|
|
83
|
+
const response = body.useTools ? await chatWithTools(messages2) : await chat(messages2, body.systemPrompt);
|
|
84
|
+
return c.json({
|
|
85
|
+
content: response.content,
|
|
86
|
+
toolsUsed: response.toolsUsed,
|
|
87
|
+
usage: {
|
|
88
|
+
inputTokens: response.inputTokens,
|
|
89
|
+
outputTokens: response.outputTokens
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("Ask API error:", error);
|
|
94
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
app.get("/api/conversations", async (c) => {
|
|
98
|
+
try {
|
|
99
|
+
const convos = await db.select().from(conversations).orderBy(desc(conversations.updatedAt)).limit(50);
|
|
100
|
+
return c.json(convos);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error("Error fetching conversations:", error);
|
|
103
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
app.get("/api/conversations/:id", async (c) => {
|
|
107
|
+
try {
|
|
108
|
+
const id = c.req.param("id");
|
|
109
|
+
const convo = await db.select().from(conversations).where(eq(conversations.id, id)).limit(1);
|
|
110
|
+
if (convo.length === 0) {
|
|
111
|
+
return c.json({ error: "Conversation not found" }, 404);
|
|
112
|
+
}
|
|
113
|
+
const msgs = await db.select().from(messages).where(eq(messages.conversationId, id)).orderBy(messages.createdAt);
|
|
114
|
+
return c.json({ conversation: convo[0], messages: msgs });
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error("Error fetching conversation:", error);
|
|
117
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
app.get("/api/memories", async (c) => {
|
|
121
|
+
try {
|
|
122
|
+
const userId = c.req.query("userId");
|
|
123
|
+
const limit = parseInt(c.req.query("limit") || "50");
|
|
124
|
+
let query = db.select().from(memories).orderBy(desc(memories.createdAt)).limit(limit);
|
|
125
|
+
const mems = await query;
|
|
126
|
+
return c.json(mems);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("Error fetching memories:", error);
|
|
129
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
app.post("/api/memories/search", async (c) => {
|
|
133
|
+
try {
|
|
134
|
+
const body = await c.req.json();
|
|
135
|
+
if (!body.query) {
|
|
136
|
+
return c.json({ error: "query is required" }, 400);
|
|
137
|
+
}
|
|
138
|
+
const results = await searchMemories(body.query, body.userId, body.limit || 5);
|
|
139
|
+
return c.json(results);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("Error searching memories:", error);
|
|
142
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
app.post("/api/memories", async (c) => {
|
|
146
|
+
try {
|
|
147
|
+
const body = await c.req.json();
|
|
148
|
+
if (!body.content) {
|
|
149
|
+
return c.json({ error: "content is required" }, 400);
|
|
150
|
+
}
|
|
151
|
+
const memory = await storeMemory({
|
|
152
|
+
content: body.content,
|
|
153
|
+
type: body.type || "semantic",
|
|
154
|
+
importance: body.importance || 5,
|
|
155
|
+
userId: body.userId,
|
|
156
|
+
source: "api"
|
|
157
|
+
});
|
|
158
|
+
return c.json(memory);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error("Error storing memory:", error);
|
|
161
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
app.get("/api/system/status", async (c) => {
|
|
165
|
+
return c.json({
|
|
166
|
+
status: "online",
|
|
167
|
+
version: "1.0.0",
|
|
168
|
+
uptime: process.uptime(),
|
|
169
|
+
memory: process.memoryUsage()
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
app.use("/*", serveStatic({ root: "./src/web/dist" }));
|
|
173
|
+
app.get("/*", serveStatic({ path: "./src/web/dist/index.html" }));
|
|
174
|
+
|
|
175
|
+
export {
|
|
176
|
+
app
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=chunk-KHNYJY2Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/inputs/api/server.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { logger } from \"hono/logger\";\n// Use platform-appropriate static file serving\nlet serveStatic: any;\ntry {\n // Bun runtime\n serveStatic = require(\"hono/bun\").serveStatic;\n} catch {\n // Fallback: no static file serving (API-only mode)\n serveStatic = () => async (_c: any, next: any) => next();\n}\nimport { chat, chatWithTools, streamChat, type Message } from \"../../core/brain\";\nimport { db, conversations, messages, memories } from \"../../db\";\nimport { desc, eq } from \"drizzle-orm\";\nimport { searchMemories, storeMemory } from \"../../core/memory\";\n\nconst app = new Hono();\n\n// Middleware\napp.use(\"*\", logger());\napp.use(\"/api/*\", cors());\n\n// Health check\napp.get(\"/health\", (c) => {\n return c.json({ status: \"ok\", timestamp: new Date().toISOString() });\n});\n\n// ===== Chat API =====\n\n// Simple chat endpoint (no tools)\napp.post(\"/api/chat\", async (c) => {\n try {\n const body = await c.req.json<{\n messages: Message[];\n systemPrompt?: string;\n }>();\n\n if (!body.messages || !Array.isArray(body.messages)) {\n return c.json({ error: \"messages array is required\" }, 400);\n }\n\n const response = await chat(body.messages, body.systemPrompt);\n\n return c.json({\n content: response.content,\n usage: {\n inputTokens: response.inputTokens,\n outputTokens: response.outputTokens,\n },\n });\n } catch (error) {\n console.error(\"Chat API error:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\n// Chat with tools endpoint\napp.post(\"/api/chat/tools\", async (c) => {\n try {\n const body = await c.req.json<{\n messages: Message[];\n userId?: string;\n }>();\n\n if (!body.messages || !Array.isArray(body.messages)) {\n return c.json({ error: \"messages array is required\" }, 400);\n }\n\n const toolsUsed: string[] = [];\n const response = await chatWithTools(body.messages, body.userId, (tool) => {\n toolsUsed.push(tool);\n });\n\n return c.json({\n content: response.content,\n toolsUsed,\n usage: {\n inputTokens: response.inputTokens,\n outputTokens: response.outputTokens,\n },\n });\n } catch (error) {\n console.error(\"Chat with tools API error:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\n// Simple single message chat\napp.post(\"/api/ask\", async (c) => {\n try {\n const body = await c.req.json<{\n message: string;\n systemPrompt?: string;\n useTools?: boolean;\n }>();\n\n if (!body.message) {\n return c.json({ error: \"message is required\" }, 400);\n }\n\n const messages: Message[] = [{ role: \"user\", content: body.message }];\n\n const response = body.useTools\n ? await chatWithTools(messages)\n : await chat(messages, body.systemPrompt);\n\n return c.json({\n content: response.content,\n toolsUsed: response.toolsUsed,\n usage: {\n inputTokens: response.inputTokens,\n outputTokens: response.outputTokens,\n },\n });\n } catch (error) {\n console.error(\"Ask API error:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\n// ===== Conversations API =====\n\napp.get(\"/api/conversations\", async (c) => {\n try {\n const convos = await db\n .select()\n .from(conversations)\n .orderBy(desc(conversations.updatedAt))\n .limit(50);\n\n return c.json(convos);\n } catch (error) {\n console.error(\"Error fetching conversations:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\napp.get(\"/api/conversations/:id\", async (c) => {\n try {\n const id = c.req.param(\"id\");\n const convo = await db\n .select()\n .from(conversations)\n .where(eq(conversations.id, id))\n .limit(1);\n\n if (convo.length === 0) {\n return c.json({ error: \"Conversation not found\" }, 404);\n }\n\n const msgs = await db\n .select()\n .from(messages)\n .where(eq(messages.conversationId, id))\n .orderBy(messages.createdAt);\n\n return c.json({ conversation: convo[0], messages: msgs });\n } catch (error) {\n console.error(\"Error fetching conversation:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\n// ===== Memories API =====\n\napp.get(\"/api/memories\", async (c) => {\n try {\n const userId = c.req.query(\"userId\");\n const limit = parseInt(c.req.query(\"limit\") || \"50\");\n\n let query = db.select().from(memories).orderBy(desc(memories.createdAt)).limit(limit);\n\n const mems = await query;\n return c.json(mems);\n } catch (error) {\n console.error(\"Error fetching memories:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\napp.post(\"/api/memories/search\", async (c) => {\n try {\n const body = await c.req.json<{ query: string; userId?: string; limit?: number }>();\n\n if (!body.query) {\n return c.json({ error: \"query is required\" }, 400);\n }\n\n const results = await searchMemories(body.query, body.userId, body.limit || 5);\n return c.json(results);\n } catch (error) {\n console.error(\"Error searching memories:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\napp.post(\"/api/memories\", async (c) => {\n try {\n const body = await c.req.json<{\n content: string;\n type?: \"episodic\" | \"semantic\" | \"procedural\";\n importance?: number;\n userId?: string;\n }>();\n\n if (!body.content) {\n return c.json({ error: \"content is required\" }, 400);\n }\n\n const memory = await storeMemory({\n content: body.content,\n type: body.type || \"semantic\",\n importance: body.importance || 5,\n userId: body.userId,\n source: \"api\",\n });\n\n return c.json(memory);\n } catch (error) {\n console.error(\"Error storing memory:\", error);\n return c.json({ error: \"Internal server error\" }, 500);\n }\n});\n\n// ===== System API =====\n\napp.get(\"/api/system/status\", async (c) => {\n return c.json({\n status: \"online\",\n version: \"1.0.0\",\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n });\n});\n\n// Serve static files from web/dist\napp.use(\"/*\", serveStatic({ root: \"./src/web/dist\" }));\n\n// Fallback to index.html for SPA routing\napp.get(\"/*\", serveStatic({ path: \"./src/web/dist/index.html\" }));\n\nexport { app };\n"],"mappings":"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","names":["messages"]}
|