feat: add conversational Telegram AI chat
All checks were successful
Codex Template Compliance / template-compliance (pull_request) Successful in 7s
Build / test-and-image (pull_request) Successful in 53s

This commit is contained in:
2026-07-05 20:39:11 +02:00
parent 9f3d7dc6a9
commit de1d9aee70
9 changed files with 404 additions and 12 deletions

View File

@@ -14,6 +14,7 @@ import { synthesize, generateIdeas } from './dashboard/inject.mjs';
import { MemoryManager } from './lib/delta/index.mjs';
import { createLLMProvider } from './lib/llm/index.mjs';
import { generateLLMIdeas } from './lib/llm/ideas.mjs';
import { TelegramChatAssistant, buildTelegramChatContext } from './lib/llm/telegram-chat.mjs';
import { TelegramAlerter } from './lib/alerts/telegram.mjs';
import { DiscordAlerter } from './lib/alerts/discord.mjs';
import { getFetchMetrics } from './apis/utils/fetch.mjs';
@@ -53,6 +54,14 @@ await intelligenceStore.init();
const llmProvider = createLLMProvider(config.llm);
const telegramAlerter = new TelegramAlerter(config.telegram);
const discordAlerter = new DiscordAlerter(config.discord || {});
const telegramChatAssistant = new TelegramChatAssistant({
provider: llmProvider,
getContext: () => buildTelegramChatContext(currentData, buildHealth()),
historyMessages: config.telegram.aiHistoryMessages,
maxInputChars: config.telegram.aiMaxInputChars,
maxTokens: config.telegram.aiMaxTokens,
timeoutMs: config.telegram.aiTimeoutMs,
});
if (llmProvider) console.log(`[Crucix] LLM enabled: ${llmProvider.name} (${llmProvider.model})`);
else if (config.llm.provider) console.warn(`[Crucix] LLM provider "${config.llm.provider}" is not configured; LLM features disabled`);
@@ -82,6 +91,7 @@ if (telegramAlerter.isConfigured) {
`Sweep in progress: ${sweepInProgress ? '🔄 Yes' : '⏸️ No'}`,
`Sources: ${sourcesOk}/${sourcesTotal} OK${sourcesFailed > 0 ? ` (${sourcesFailed} failed)` : ''}`,
`LLM: ${llmStatus}`,
`AI chat: ${config.telegram.aiChatEnabled && telegramChatAssistant.isConfigured ? 'enabled' : 'disabled'}`,
`SSE clients: ${sseClients.size}`,
`Dashboard: http://localhost:${config.port}`,
].join('\n');
@@ -148,6 +158,26 @@ if (telegramAlerter.isConfigured) {
return sections.join('\n');
});
const answerTelegramQuestion = async (question, msg) => {
if (!config.telegram.aiChatEnabled) {
return { text: 'AI chat is disabled by TELEGRAM_AI_CHAT_ENABLED.', parseMode: null };
}
const text = await telegramChatAssistant.reply(question, { chatId: msg?.chat?.id || config.telegram.chatId });
return { text, parseMode: null };
};
telegramAlerter.onMessage((text, msg) => answerTelegramQuestion(text, msg));
telegramAlerter.onCommand('/ask', async (args, _messageId, msg) => {
if (!args.trim()) return { text: 'Usage: /ask <question>', parseMode: null };
return answerTelegramQuestion(args, msg);
});
telegramAlerter.onCommand('/reset', async (_args, _messageId, msg) => {
telegramChatAssistant.reset(msg?.chat?.id || config.telegram.chatId);
return { text: 'AI conversation history cleared.', parseMode: null };
});
telegramAlerter.onCommand('/portfolio', async () => {
return '📊 Portfolio integration requires Alpaca MCP connection.\nUse the Crucix dashboard or Claude agent for portfolio queries.';
});
@@ -547,6 +577,11 @@ function buildHealth() {
sourceHealth: currentData?.sourceHealth || currentData?.health || [],
llm: getLLMStatus(),
telegramEnabled: !!(config.telegram.botToken && config.telegram.chatId),
telegramAiChat: {
enabled: Boolean(config.telegram.aiChatEnabled && telegramChatAssistant.isConfigured),
historyMessages: config.telegram.aiHistoryMessages,
maxInputChars: config.telegram.aiMaxInputChars,
},
discordEnabled: !!(config.discord?.botToken || config.discord?.webhookUrl),
terminalActionsEnabled: config.terminalActionsEnabled,
terminalActionsTokenRequired: !!config.sweepToken,