Files
microdao-daarion/MONITOR-MESSAGES-PERSIST-FIX.md
Apple 744c149300
Some checks failed
Build and Deploy Docs / build-and-deploy (push) Has been cancelled
Add automated session logging system
- Created logs/ structure (sessions, operations, incidents)
- Added session-start/log/end scripts
- Installed Git hooks for auto-logging commits/pushes
- Added shell integration for zsh
- Created CHANGELOG.md
- Documented today's session (2026-01-10)
2026-01-10 04:53:17 -08:00

382 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ✅ Monitor Agent - Виправлення персистентності повідомлень
**Дата:** 2025-11-23
**Статус:** ✅ Повідомлення тепер зберігаються і не зникають
---
## 🎯 Проблема
**Симптоми:**
- Вікно чату порожнє при відкритті
- Повідомлення з'являються в консолі, але зникають з UI
- Події `project-change` відправляються, але не відображаються
**Консоль показувала:**
```
✅ CustomEvent dispatched successfully
✅ Adding project change message to chat: change-...
📝 Total messages after add: 1
```
**Але в UI нічого не було!**
---
## 🔍 Причина
1. **Повідомлення не зберігалися між перезавантаженнями**
- При кожному рефреші всі повідомлення зникали
- Не було персистентності в `localStorage`
2. **Дублікати видалялися занадто агресивно**
- Перевірка на дублікати виконувалася ДО додавання
- Це блокувало деякі валідні повідомлення
3. **Події не проходили через Shadow DOM**
- `CustomEvent` не мав `bubbles: true` і `composed: true`
- Це могло блокувати події в деяких випадках
---
## ✅ Рішення
### 1. Додано персистентність в localStorage
**Файл:** `src/pages/DagiMonitorPage.tsx`
```typescript
// Завантаження повідомлень при ініціалізації
const [messages, setMessages] = React.useState<ChatMessage[]>(() => {
try {
const saved = localStorage.getItem('monitor-chat-messages');
if (saved) {
const parsed = JSON.parse(saved);
console.log('📦 Loaded messages from localStorage:', parsed.length);
return parsed;
}
} catch (error) {
console.warn('Could not load messages from localStorage:', error);
}
return [];
});
// Збереження повідомлень при зміні
useEffect(() => {
if (messages.length > 0) {
try {
localStorage.setItem('monitor-chat-messages', JSON.stringify(messages.slice(0, 100)));
console.log('💾 Saved messages to localStorage:', messages.length);
} catch (error) {
console.warn('Could not save messages to localStorage:', error);
}
}
}, [messages]);
```
### 2. Спрощено обробку project-change подій
**Було:**
```typescript
const handleProjectChange = (event: Event) => {
// ... складна логіка з ref ...
setMessages((prev) => {
const isDuplicate = prev.some((msg) =>
msg.content === message || // Порівнював контент!
(msg.id && msg.id === `project-${change.id}`)
);
if (isDuplicate) {
return prev; // Блокував додавання
}
// ...
});
};
```
**Стало:**
```typescript
const handleProjectChange = (event: Event) => {
const customEvent = event as CustomEvent;
const { message, change } = customEvent.detail;
// Створюємо повідомлення одразу
const newMessage: ChatMessage = {
id: `project-${change?.id || Date.now()}`,
role: 'assistant',
content: message,
timestamp: change?.timestamp || new Date().toISOString(),
};
// Додаємо (перевірка дублікатів тільки за ID)
setMessages((prev) => {
if (newMessage.id) {
const isDuplicate = prev.some((msg) => msg.id === newMessage.id);
if (isDuplicate) return prev;
}
return [newMessage, ...prev];
});
};
```
### 3. Покращено emitChangeEvent
**Файл:** `src/services/projectChangeTracker.ts`
```typescript
private emitChangeEvent(message: string, change: ProjectChange) {
if (typeof window !== 'undefined') {
try {
const event = new CustomEvent('project-change', {
detail: { message, change },
bubbles: true, // Дозволяємо події спливати
composed: true, // Проходити через Shadow DOM
});
window.dispatchEvent(event);
// ДОДАТКОВО: зберігаємо в localStorage
const storageKey = 'monitor-latest-changes';
const existing = localStorage.getItem(storageKey);
const changes = existing ? JSON.parse(existing) : [];
changes.unshift({ message, change, timestamp: Date.now() });
localStorage.setItem(storageKey, JSON.stringify(changes.slice(0, 50)));
} catch (error) {
console.error('Error:', error);
}
}
}
```
---
## 📊 Архітектура персистентності
```
┌─────────────────────────────────────────────────────┐
│ ProjectChangeTracker │
│ - Генерує зміни │
│ - Відправляє CustomEvent │
│ - Зберігає в localStorage (backup) │
└─────────────────────────────────────────────────────┘
CustomEvent 'project-change'
┌─────────────────────────────────────────────────────┐
│ DagiMonitorPage │
│ - Слухає CustomEvent │
│ - Додає до messages state │
│ - Автоматично зберігає в localStorage │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ localStorage │
│ - 'monitor-chat-messages': останні 100 повідомлень│
│ - 'monitor-latest-changes': останні 50 змін │
└─────────────────────────────────────────────────────┘
При перезавантаженні сторінки
┌─────────────────────────────────────────────────────┐
│ DagiMonitorPage (нова сесія) │
│ - Завантажує з localStorage │
│ - Відновлює повідомлення │
│ - Продовжує слухати нові події │
└─────────────────────────────────────────────────────┘
```
---
## 🧪 Тестування
### 1. Перевірити персистентність
1. Відкрити: `http://localhost:8899/dagi-monitor`
2. Почекати 5 секунд (мають з'явитися повідомлення)
3. **Натиснути F5 (рефреш)**
4. **Повідомлення мають залишитися!**
### 2. Перевірити автоматичні повідомлення
1. Відкрити чат
2. Нічого не натискати
3. Через 3-5 секунд з'являються нові повідомлення
4. **Повідомлення не зникають!**
### 3. Перевірити localStorage
```javascript
// В консолі браузера
JSON.parse(localStorage.getItem('monitor-chat-messages')).length
// Має показати кількість повідомлень (наприклад, 10)
JSON.parse(localStorage.getItem('monitor-latest-changes')).length
// Має показати кількість змін (наприклад, 15)
```
### 4. Очистити повідомлення
```javascript
// В консолі браузера (якщо потрібно почати з чистого аркуша)
localStorage.removeItem('monitor-chat-messages');
localStorage.removeItem('monitor-latest-changes');
location.reload();
```
---
## 📝 localStorage Структура
### `monitor-chat-messages`
Зберігає останні 100 повідомлень чату:
```json
[
{
"id": "project-change-1763904714538",
"role": "assistant",
"content": "🤖 **Monitor Agent:** 🔧 MODIFIED: ...node-1/swapper [node-1]",
"timestamp": "2025-11-23T05:31:54.538Z"
},
...
]
```
### `monitor-latest-changes`
Зберігає останні 50 змін (backup):
```json
[
{
"message": "🤖 **Monitor Agent:** 🔧 MODIFIED: ...",
"change": {
"id": "change-1763904714538-abc",
"type": "service",
"action": "modified",
"path": "nodes/node-1/swapper",
"timestamp": "2025-11-23T05:31:54.538Z",
"details": { "node_id": "node-1", "service": "swapper" }
},
"timestamp": 1763904714538
},
...
]
```
---
## ⚙️ Конфігурація
### Кількість повідомлень для збереження
**Файл:** `src/pages/DagiMonitorPage.tsx`
```typescript
// Зберігаємо останні 100 повідомлень
localStorage.setItem('monitor-chat-messages', JSON.stringify(messages.slice(0, 100)));
```
**Можна змінити:**
- `50` - для менших пристроїв
- `100` - оптимально
- `200` - для більшої історії
### Кількість змін для backup
**Файл:** `src/services/projectChangeTracker.ts`
```typescript
// Зберігаємо останні 50 змін
localStorage.setItem(storageKey, JSON.stringify(changes.slice(0, 50)));
```
---
## 🎯 Результат
### До виправлення:
**Проблеми:**
- Вікно порожнє
- Повідомлення зникають
- Немає персистентності
- Події не проходять
### Після виправлення:
**Результат:**
- Повідомлення залишаються в чаті
- Персистентність між сесіями
- Події проходять через Shadow DOM
- Backup в localStorage
---
## 🐛 Дебаг
### Якщо повідомлення не з'являються:
1. **Перевірити консоль:**
```javascript
// Має бути:
"✅ Subscribed to project-change events"
"✅ CustomEvent dispatched: true"
"✅ Adding project change message to chat: ..."
"💾 Saved messages to localStorage: ..."
```
2. **Перевірити localStorage:**
```javascript
console.log(localStorage.getItem('monitor-chat-messages'));
```
3. **Перевірити ProjectChangeTracker:**
```javascript
// В консолі
"🚀 Starting real-time change tracking (every 3 seconds)..."
"🔍 Checking for real-time changes..."
```
4. **Очистити localStorage і рефреш:**
```javascript
localStorage.clear();
location.reload();
```
---
## ✅ Чекліст
- [x] Додано завантаження з localStorage при ініціалізації
- [x] Додано збереження в localStorage при зміні messages
- [x] Спрощено handleProjectChange (без ref)
- [x] Додано bubbles: true, composed: true для CustomEvent
- [x] Додано backup в localStorage в emitChangeEvent
- [x] Зберігаємо останні 100 повідомлень
- [x] Зберігаємо останні 50 змін (backup)
- [x] Перевірка дублікатів тільки за ID
- [x] Логування для дебагу
---
**Статус:** ✅ Готово! Повідомлення тепер зберігаються!
**Тестуйте:** Відкрийте `http://localhost:8899/dagi-monitor` і натисніть F5 - повідомлення залишаться!