Skip to content

Commit 80a572a

Browse files
committed
feat: complete Matrix session collaboration backend implementation
- Add Matrix session services (MatrixInviteStateService, MatrixSessionService, UnifiedSessionService) - Implement Matrix chat components and session management - Add comprehensive Matrix integration across UI components - Update session handling and message streaming for Matrix compatibility - Enhance chat input and base chat components for Matrix collaboration - Add Matrix notification and session list view support - Integrate Matrix services with existing Goose chat infrastructure This completes the huge backend change that allows Matrix sessions to be written to the backend as a session.
1 parent 43852b2 commit 80a572a

File tree

14 files changed

+1201
-117
lines changed

14 files changed

+1201
-117
lines changed

ui/desktop/src/App.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,25 @@ export function AppInner() {
364364
const handleOpenChat = useCallback((roomId: string, senderId: string) => {
365365
console.log('📱 Opening chat for room:', roomId, 'sender:', senderId);
366366

367-
// Navigate to peers view with chat parameters
368-
navigate('/peers', {
369-
state: {
370-
openChat: true,
371-
roomId,
372-
senderId
373-
}
374-
});
367+
// For Matrix rooms (starting with !), navigate directly to pair view with Matrix parameters
368+
if (roomId.startsWith('!')) {
369+
console.log('📱 Opening Matrix shared session for room:', roomId);
370+
const searchParams = new URLSearchParams({
371+
matrixMode: 'true',
372+
matrixRoomId: roomId,
373+
matrixRecipientId: senderId
374+
});
375+
navigate(`/pair?${searchParams.toString()}`);
376+
} else {
377+
// For non-Matrix rooms, navigate to peers view
378+
navigate('/peers', {
379+
state: {
380+
openChat: true,
381+
roomId,
382+
senderId
383+
}
384+
});
385+
}
375386
}, [navigate]);
376387

377388
useEffect(() => {

ui/desktop/src/components/BaseChat.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ function BaseChatContent({
557557
</div>
558558

559559
<ChatInput
560-
sessionId={chat.sessionId}
560+
sessionId={(customChatInputProps as any)?.sessionId || chat.sessionId} // Allow override from customChatInputProps
561561
handleSubmit={handleSubmit}
562562
chatState={chatState}
563563
onStop={onStopGoose}

ui/desktop/src/components/ChatInput.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,15 +366,32 @@ export default function ChatInput({
366366
sessionTitle: isMatrixRoom && sessionId ? `Matrix Room ${sessionId.substring(0, 8)}` : `Chat Session ${sessionId?.substring(0, 8) || 'default'}`,
367367
messages: messages, // Always sync messages
368368
onMessageSync: (message) => {
369-
console.log('💬 ChatInput: Received message from useSessionSharing:', message);
369+
console.log('💬 ChatInput: *** RECEIVED MESSAGE FROM useSessionSharing ***', message);
370+
console.log('💬 ChatInput: Message details:', {
371+
id: message.id,
372+
role: message.role,
373+
content: Array.isArray(message.content) ? message.content[0]?.text?.substring(0, 50) + '...' : 'N/A',
374+
sender: message.sender?.displayName || message.sender?.userId || 'unknown',
375+
hasAppendFunction: !!append,
376+
appendFunctionType: typeof append,
377+
sessionId: sessionId,
378+
isMatrixRoom: isMatrixRoom
379+
});
370380

371381
// For Matrix rooms, messages from Matrix should appear normally
372382
// For regular sessions, messages should also appear normally
373383
// The key is that useSessionSharing handles both cases the same way
374384
if (append) {
375-
append(message);
385+
console.log('💬 ChatInput: *** CALLING APPEND FUNCTION WITH MESSAGE ***');
386+
try {
387+
const result = append(message);
388+
console.log('💬 ChatInput: *** APPEND FUNCTION RETURNED ***:', result);
389+
console.log('💬 ChatInput: *** APPEND SUCCESSFUL - MESSAGE SHOULD APPEAR IN CHAT ***');
390+
} catch (error) {
391+
console.error('💬 ChatInput: *** APPEND FUNCTION FAILED ***:', error);
392+
}
376393
} else {
377-
console.warn('⚠️ ChatInput: append function is not available!');
394+
console.warn('⚠️ ChatInput: *** APPEND FUNCTION IS NOT AVAILABLE! ***');
378395
}
379396
},
380397
initialRoomId: isMatrixRoom ? sessionId : null, // Pass Matrix room ID if it's a Matrix room

ui/desktop/src/components/GooseChat.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import React, { useState, useEffect } from 'react';
2-
import { useNavigate } from 'react-router-dom';
2+
import { useNavigate, useLocation } from 'react-router-dom';
33
import { useMatrix } from '../contexts/MatrixContext';
44
import { GooseChatMessage } from '../services/MatrixService';
55

66
const GooseChat: React.FC = () => {
77
const navigate = useNavigate();
8+
const location = useLocation();
89
const {
910
isConnected,
1011
gooseInstances,
@@ -26,15 +27,36 @@ const GooseChat: React.FC = () => {
2627
const [taskDescription, setTaskDescription] = useState('');
2728
const [collaborationProject, setCollaborationProject] = useState('');
2829

29-
// Listen for incoming Goose messages
30+
// Check if we're in a Matrix shared session context
31+
const isInMatrixSharedSession = () => {
32+
// Check URL parameters for Matrix mode
33+
const searchParams = new URLSearchParams(location.search);
34+
const matrixMode = searchParams.get('matrixMode') === 'true';
35+
const matrixRoomId = searchParams.get('matrixRoomId');
36+
37+
// Check if we're on a route that uses Matrix shared sessions
38+
const isMatrixRoute = (location.pathname === '/' || location.pathname === '/pair') && (matrixMode || matrixRoomId);
39+
40+
return isMatrixRoute;
41+
};
42+
43+
// Listen for incoming Goose messages - but only when not in Matrix shared session
3044
useEffect(() => {
45+
// Don't process Goose messages if we're in a Matrix shared session context
46+
// to prevent interference with the main chat
47+
if (isInMatrixSharedSession()) {
48+
console.log('🚫 GooseChat: Disabling message processing - Matrix shared session is active');
49+
return;
50+
}
51+
52+
console.log('✅ GooseChat: Setting up Goose message listener');
3153
const unsubscribe = onGooseMessage((message: GooseChatMessage) => {
32-
console.log('🦆 Received Goose message:', message);
54+
console.log('🦆 GooseChat: Received Goose message:', message);
3355
setMessages(prev => [...prev, message]);
3456
});
3557

3658
return unsubscribe;
37-
}, [onGooseMessage]);
59+
}, [onGooseMessage, location.search, location.pathname]);
3860

3961
const handleSendMessage = async () => {
4062
if (!messageText.trim() || !selectedRoom) return;

ui/desktop/src/components/MatrixChat.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface MatrixChatProps {
1010
recipientId?: string;
1111
onBack?: () => void;
1212
className?: string;
13+
disableMessageHandling?: boolean; // Add prop to disable message handling when used alongside useSessionSharing
1314
}
1415

1516
interface ChatMessage {
@@ -28,6 +29,7 @@ const MatrixChat: React.FC<MatrixChatProps> = ({
2829
recipientId,
2930
onBack,
3031
className = '',
32+
disableMessageHandling = false,
3133
}) => {
3234
const {
3335
currentUser,
@@ -58,7 +60,12 @@ const MatrixChat: React.FC<MatrixChatProps> = ({
5860

5961
// Listen for messages in this room
6062
useEffect(() => {
61-
if (!roomId || !currentUser) return;
63+
if (!roomId || !currentUser || disableMessageHandling) {
64+
if (disableMessageHandling) {
65+
console.log('🚫 MatrixChat message handling disabled - useSessionSharing is handling messages');
66+
}
67+
return;
68+
}
6269

6370
const handleRegularMessage = (messageData: any) => {
6471
const { content, sender, roomId: msgRoomId, timestamp, senderInfo } = messageData;
@@ -131,7 +138,7 @@ const MatrixChat: React.FC<MatrixChatProps> = ({
131138
unsubscribeRegular();
132139
unsubscribeGoose();
133140
};
134-
}, [roomId, currentUser, onMessage, onGooseMessage]);
141+
}, [roomId, currentUser, onMessage, onGooseMessage, disableMessageHandling]);
135142

136143
// Auto-scroll to bottom when new messages arrive
137144
useEffect(() => {

ui/desktop/src/components/MessageNotification.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
22
import { motion, AnimatePresence } from 'framer-motion';
33
import { MessageCircle, X, User, Clock } from 'lucide-react';
44
import { useMatrix } from '../contexts/MatrixContext';
5+
import { useLocation } from 'react-router-dom';
56
import AvatarImage from './AvatarImage';
67

78
interface MessageNotificationData {
@@ -31,9 +32,20 @@ const MessageNotification: React.FC<MessageNotificationProps> = ({
3132
currentUser,
3233
} = useMatrix();
3334

35+
const location = useLocation();
36+
3437
const [notifications, setNotifications] = useState<MessageNotificationData[]>([]);
3538
const [dismissedIds, setDismissedIds] = useState<Set<string>>(new Set());
3639

40+
// Helper function to get current active Matrix room ID if in shared session mode
41+
const getCurrentActiveMatrixRoom = () => {
42+
const searchParams = new URLSearchParams(location.search);
43+
const isMatrixMode = searchParams.get('matrixMode') === 'true';
44+
const matrixRoomId = searchParams.get('matrixRoomId');
45+
46+
return isMatrixMode && matrixRoomId ? matrixRoomId : null;
47+
};
48+
3749
// Listen for incoming messages
3850
useEffect(() => {
3951
if (!isConnected || !currentUser) return;
@@ -45,6 +57,13 @@ const MessageNotification: React.FC<MessageNotificationProps> = ({
4557
// Only show notifications for messages from others
4658
if (sender === currentUser.userId) return;
4759

60+
// Skip notifications for messages from the currently active Matrix room (shared session)
61+
const activeMatrixRoom = getCurrentActiveMatrixRoom();
62+
if (activeMatrixRoom && roomId === activeMatrixRoom) {
63+
console.log('📱 Skipping notification for message from active Matrix room:', roomId);
64+
return;
65+
}
66+
4867
// Filter out very old messages (more than 2 minutes old) to prevent spam on startup
4968
const messageAge = Date.now() - new Date(timestamp).getTime();
5069
const twoMinutesInMs = 2 * 60 * 1000;
@@ -86,6 +105,13 @@ const MessageNotification: React.FC<MessageNotificationProps> = ({
86105
// Only show notifications for messages from others
87106
if (metadata?.isFromSelf) return;
88107

108+
// Skip notifications for messages from the currently active Matrix room (shared session)
109+
const activeMatrixRoom = getCurrentActiveMatrixRoom();
110+
if (activeMatrixRoom && roomId === activeMatrixRoom) {
111+
console.log('🦆 Skipping Goose notification for message from active Matrix room:', roomId);
112+
return;
113+
}
114+
89115
// Filter out old messages
90116
const messageAge = Date.now() - new Date(timestamp).getTime();
91117
const twoMinutesInMs = 2 * 60 * 1000;

0 commit comments

Comments
 (0)