From b50376dfdb9bd65af808e66c159b574bb88cf73c Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Wed, 28 Jan 2026 12:40:28 +0100 Subject: [PATCH] fix(matrix-bots): update to matrix-bot-sdk v0.7 API - Import LogLevel separately instead of LogService.LogLevel - Change sendTyping to setTyping - Use any type for event handler to avoid generic type issues - Fix Buffer to Uint8Array conversion for OpenAI File API Co-Authored-By: Claude Opus 4.5 --- .../src/bot/matrix.service.ts | 72 ++++++++++++------- .../src/bot/matrix.service.ts | 60 +++++++++++----- .../transcription/transcription.service.ts | 2 +- .../src/bot/matrix.service.ts | 9 ++- 4 files changed, 94 insertions(+), 49 deletions(-) diff --git a/services/matrix-ollama-bot/src/bot/matrix.service.ts b/services/matrix-ollama-bot/src/bot/matrix.service.ts index d1f743f89..6af8099b3 100644 --- a/services/matrix-ollama-bot/src/bot/matrix.service.ts +++ b/services/matrix-ollama-bot/src/bot/matrix.service.ts @@ -6,8 +6,7 @@ import { AutojoinRoomsMixin, RichConsoleLogger, LogService, - MessageEvent, - RoomEvent, + LogLevel, } from 'matrix-bot-sdk'; import { OllamaService } from '../ollama/ollama.service'; import { SYSTEM_PROMPTS } from '../config/configuration'; @@ -45,7 +44,7 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { // Setup logging LogService.setLogger(new RichConsoleLogger()); - LogService.setLevel(LogService.LogLevel.INFO); + LogService.setLevel(LogLevel.INFO); // Storage for sync token persistence const storage = new SimpleFsStorageProvider(storagePath || './data/bot-storage.json'); @@ -91,7 +90,7 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { return this.sessions.get(senderId)!; } - private async handleRoomMessage(roomId: string, event: RoomEvent) { + private async handleRoomMessage(roomId: string, event: any) { // Ignore messages from self if (event.sender === this.botUserId) return; @@ -102,7 +101,7 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { } // Only handle text messages - const content = event.content; + const content = event.content as { msgtype?: string; body?: string }; if (content.msgtype !== 'm.text') return; const body = content.body; @@ -151,7 +150,10 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { break; default: - await this.sendMessage(roomId, `Unbekannter Befehl: !${command}\n\nVerwende !help für eine Liste der Befehle.`); + await this.sendMessage( + roomId, + `Unbekannter Befehl: !${command}\n\nVerwende !help für eine Liste der Befehle.` + ); } } @@ -197,13 +199,19 @@ Schreibe einfach eine Nachricht und ich antworte! }) .join('\n'); - await this.sendMessage(roomId, `**Verfügbare Modelle:**\n\n${modelList}\n\nWechseln mit: \`!model [name]\``); + await this.sendMessage( + roomId, + `**Verfügbare Modelle:**\n\n${modelList}\n\nWechseln mit: \`!model [name]\`` + ); } private async setModel(roomId: string, sender: string, modelName: string) { if (!modelName) { const session = this.getSession(sender); - await this.sendMessage(roomId, `Aktuelles Modell: \`${session.model}\`\n\nVerwendung: \`!model gemma3:4b\``); + await this.sendMessage( + roomId, + `Aktuelles Modell: \`${session.model}\`\n\nVerwendung: \`!model gemma3:4b\`` + ); return; } @@ -212,7 +220,10 @@ Schreibe einfach eine Nachricht und ich antworte! if (!exists) { const available = models.map((m) => m.name).join(', '); - await this.sendMessage(roomId, `Modell "${modelName}" nicht gefunden.\n\nVerfügbar: ${available}`); + await this.sendMessage( + roomId, + `Modell "${modelName}" nicht gefunden.\n\nVerfügbar: ${available}` + ); return; } @@ -230,14 +241,21 @@ Schreibe einfach eine Nachricht und ich antworte! if (!mode) { const session = this.getSession(sender); const currentMode = - Object.entries(SYSTEM_PROMPTS).find(([_, v]) => v === session.systemPrompt)?.[0] || 'custom'; - await this.sendMessage(roomId, `Aktueller Modus: \`${currentMode}\`\n\nVerfügbar: ${availableModes.join(', ')}`); + Object.entries(SYSTEM_PROMPTS).find(([_, v]) => v === session.systemPrompt)?.[0] || + 'custom'; + await this.sendMessage( + roomId, + `Aktueller Modus: \`${currentMode}\`\n\nVerfügbar: ${availableModes.join(', ')}` + ); return; } const normalizedMode = mode.toLowerCase(); if (!SYSTEM_PROMPTS[normalizedMode]) { - await this.sendMessage(roomId, `Unbekannter Modus: ${mode}\n\nVerfügbar: ${availableModes.join(', ')}`); + await this.sendMessage( + roomId, + `Unbekannter Modus: ${mode}\n\nVerfügbar: ${availableModes.join(', ')}` + ); return; } @@ -277,7 +295,7 @@ Schreibe einfach eine Nachricht und ich antworte! const session = this.getSession(sender); // Send typing indicator - await this.client.sendTyping(roomId, true, 30000); + await this.client.setTyping(roomId, true, 30000); try { // Add user message to history @@ -300,12 +318,12 @@ Schreibe einfach eine Nachricht und ich antworte! session.history.push({ role: 'assistant', content: response }); // Stop typing indicator - await this.client.sendTyping(roomId, false); + await this.client.setTyping(roomId, false); // Send response (Matrix has higher message limits than Telegram) await this.sendMessage(roomId, response); } catch (error) { - await this.client.sendTyping(roomId, false); + await this.client.setTyping(roomId, false); this.logger.error(`Error processing message:`, error); const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler'; await this.sendMessage(roomId, `❌ Fehler: ${errorMessage}`); @@ -325,16 +343,18 @@ Schreibe einfach eine Nachricht und ich antworte! } private markdownToHtml(markdown: string): string { - return markdown - // Code blocks - .replace(/```(\w+)?\n([\s\S]*?)```/g, '
$2
') - // Inline code - .replace(/`([^`]+)`/g, '$1') - // Bold - .replace(/\*\*([^*]+)\*\*/g, '$1') - // Italic - .replace(/\*([^*]+)\*/g, '$1') - // Line breaks - .replace(/\n/g, '
'); + return ( + markdown + // Code blocks + .replace(/```(\w+)?\n([\s\S]*?)```/g, '
$2
') + // Inline code + .replace(/`([^`]+)`/g, '$1') + // Bold + .replace(/\*\*([^*]+)\*\*/g, '$1') + // Italic + .replace(/\*([^*]+)\*/g, '$1') + // Line breaks + .replace(/\n/g, '
') + ); } } diff --git a/services/matrix-project-doc-bot/src/bot/matrix.service.ts b/services/matrix-project-doc-bot/src/bot/matrix.service.ts index 60e4ec0ac..ef0dc686d 100644 --- a/services/matrix-project-doc-bot/src/bot/matrix.service.ts +++ b/services/matrix-project-doc-bot/src/bot/matrix.service.ts @@ -6,8 +6,7 @@ import { AutojoinRoomsMixin, RichConsoleLogger, LogService, - MessageEvent, - RoomEvent, + LogLevel, } from 'matrix-bot-sdk'; import { ProjectService } from '../project/project.service'; import { MediaService } from '../media/media.service'; @@ -44,7 +43,7 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { } LogService.setLogger(new RichConsoleLogger()); - LogService.setLevel(LogService.LogLevel.INFO); + LogService.setLevel(LogLevel.INFO); const storage = new SimpleFsStorageProvider(storagePath || './data/bot-storage.json'); this.client = new MatrixClient(homeserverUrl!, accessToken, storage); @@ -71,15 +70,15 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { return this.allowedUsers.includes(userId); } - private async handleRoomMessage(roomId: string, event: RoomEvent) { + private async handleRoomMessage(roomId: string, event: any) { if (event.sender === this.botUserId) return; if (!this.isAllowed(event.sender)) return; - const content = event.content; + const content = event.content as { msgtype?: string; body?: string; url?: string; info?: any }; const msgtype = content.msgtype; if (msgtype === 'm.text') { - const body = content.body; + const body = content.body || ''; if (body.startsWith('!')) { await this.handleCommand(roomId, event.sender, body); } else { @@ -167,7 +166,10 @@ ${styles} private async createProject(roomId: string, sender: string, name: string) { if (!name) { - await this.sendMessage(roomId, 'Verwendung: `!new Projektname`\n\nBeispiel: `!new Gartenhaus-Renovierung`'); + await this.sendMessage( + roomId, + 'Verwendung: `!new Projektname`\n\nBeispiel: `!new Gartenhaus-Renovierung`' + ); return; } @@ -185,7 +187,10 @@ ${styles} ); } catch (error) { this.logger.error('Failed to create project:', error); - await this.sendMessage(roomId, `❌ Fehler: ${error instanceof Error ? error.message : 'Unbekannt'}`); + await this.sendMessage( + roomId, + `❌ Fehler: ${error instanceof Error ? error.message : 'Unbekannt'}` + ); } } @@ -208,12 +213,18 @@ ${styles} }) ); - await this.sendMessage(roomId, `**📂 Deine Projekte:**\n\n${projectList.join('\n\n')}\n\nWechseln mit: \`!switch [ID]\``); + await this.sendMessage( + roomId, + `**📂 Deine Projekte:**\n\n${projectList.join('\n\n')}\n\nWechseln mit: \`!switch [ID]\`` + ); } private async switchProject(roomId: string, sender: string, idPrefix: string) { if (!idPrefix) { - await this.sendMessage(roomId, 'Verwendung: `!switch [ID]`\n\nZeige Projekte mit `!projects`'); + await this.sendMessage( + roomId, + 'Verwendung: `!switch [ID]`\n\nZeige Projekte mit `!projects`' + ); return; } @@ -278,7 +289,10 @@ ${styles} .map(([key, value]) => `**${key}** - ${value.name}\n_${value.prompt.slice(0, 80)}..._`) .join('\n\n'); - await this.sendMessage(roomId, `**📝 Verfügbare Blog-Stile:**\n\n${styles}\n\nVerwendung: \`!generate [stil]\``); + await this.sendMessage( + roomId, + `**📝 Verfügbare Blog-Stile:**\n\n${styles}\n\nVerwendung: \`!generate [stil]\`` + ); } private async generateBlogpost(roomId: string, sender: string, style: string) { @@ -300,18 +314,21 @@ ${styles} } await this.sendMessage(roomId, '🚀 Generiere Blogbeitrag...\n\nDas kann einen Moment dauern.'); - await this.client.sendTyping(roomId, true, 60000); + await this.client.setTyping(roomId, true, 60000); try { const content = await this.generationService.generateBlogpost(projectId, selectedStyle); - await this.client.sendTyping(roomId, false); + await this.client.setTyping(roomId, false); await this.sendMessage(roomId, content); await this.sendMessage(roomId, '✅ Blogbeitrag erstellt!\n\nExportieren mit `!export`'); } catch (error) { - await this.client.sendTyping(roomId, false); + await this.client.setTyping(roomId, false); this.logger.error('Generation failed:', error); - await this.sendMessage(roomId, `❌ Fehler: ${error instanceof Error ? error.message : 'Unbekannt'}`); + await this.sendMessage( + roomId, + `❌ Fehler: ${error instanceof Error ? error.message : 'Unbekannt'}` + ); } } @@ -324,7 +341,10 @@ ${styles} const latest = await this.generationService.getLatestGeneration(projectId); if (!latest) { - await this.sendMessage(roomId, 'Noch kein Blogbeitrag generiert.\n\nErstelle einen mit `!generate`'); + await this.sendMessage( + roomId, + 'Noch kein Blogbeitrag generiert.\n\nErstelle einen mit `!generate`' + ); return; } @@ -404,7 +424,13 @@ ${styles} const contentType = content.info?.mimetype || 'audio/ogg'; const duration = Math.round((content.info?.duration || 0) / 1000); - const item = await this.mediaService.processVoice(projectId, buffer, contentType, mxcUrl, duration); + const item = await this.mediaService.processVoice( + projectId, + buffer, + contentType, + mxcUrl, + duration + ); const stats = await this.projectService.getStats(projectId); let reply = `✅ Sprachnotiz gespeichert! (${stats.voices} gesamt)`; diff --git a/services/matrix-project-doc-bot/src/transcription/transcription.service.ts b/services/matrix-project-doc-bot/src/transcription/transcription.service.ts index 6eca0b5d6..c553ce208 100644 --- a/services/matrix-project-doc-bot/src/transcription/transcription.service.ts +++ b/services/matrix-project-doc-bot/src/transcription/transcription.service.ts @@ -27,7 +27,7 @@ export class TranscriptionService { } // Create a File-like object for the API - const file = new File([audioBuffer], 'audio.ogg', { type: 'audio/ogg' }); + const file = new File([new Uint8Array(audioBuffer)], 'audio.ogg', { type: 'audio/ogg' }); const response = await this.openai.audio.transcriptions.create({ file, diff --git a/services/matrix-stats-bot/src/bot/matrix.service.ts b/services/matrix-stats-bot/src/bot/matrix.service.ts index 666a81f72..578866a6f 100644 --- a/services/matrix-stats-bot/src/bot/matrix.service.ts +++ b/services/matrix-stats-bot/src/bot/matrix.service.ts @@ -6,8 +6,7 @@ import { AutojoinRoomsMixin, RichConsoleLogger, LogService, - MessageEvent, - RoomEvent, + LogLevel, } from 'matrix-bot-sdk'; import { AnalyticsService } from '../analytics/analytics.service'; import { UsersService } from '../users/users.service'; @@ -38,7 +37,7 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { } LogService.setLogger(new RichConsoleLogger()); - LogService.setLevel(LogService.LogLevel.INFO); + LogService.setLevel(LogLevel.INFO); const storage = new SimpleFsStorageProvider(storagePath || './data/bot-storage.json'); this.client = new MatrixClient(homeserverUrl!, accessToken, storage); @@ -61,10 +60,10 @@ export class MatrixService implements OnModuleInit, OnModuleDestroy { } } - private async handleRoomMessage(roomId: string, event: RoomEvent) { + private async handleRoomMessage(roomId: string, event: any) { if (event.sender === this.botUserId) return; - const content = event.content; + const content = event.content as { msgtype?: string; body?: string }; if (content.msgtype !== 'm.text') return; const body = content.body;