fix: make consolidation API async with background task + increased timeout

Three fixes for consolidation reliability:

1. Fire-and-forget API: POST /memory/consolidate now launches consolidation
   as an asyncio background task and returns immediately. The old approach
   blocked until Cat's WS response, which could take 5+ minutes (LLM
   extraction calls), exceeding both the WS timeout and browser fetch
   timeout. Web UI now polls /memory/status to track completion.

2. Increased timeout: cat_client.trigger_consolidation() timeout raised
   from 300s to 600s (configurable via parameter). Logs unexpected WS
   message types for debugging.

3. Better logging: Consolidation log messages prefixed with 🌙 for
   grep-friendliness. cat_client errors include exc_info=True for
   traceback visibility. Web UI shows elapsed time while polling.
This commit is contained in:
2026-05-17 11:31:26 +03:00
parent 46ea4f2c53
commit a39aca2415
3 changed files with 129 additions and 26 deletions

View File

@@ -96,18 +96,54 @@ async function triggerConsolidation() {
btn.disabled = true;
btn.textContent = '⏳ Running...';
status.textContent = 'Consolidation in progress (this may take a few minutes)...';
status.style.color = '#dcb06f';
resultDiv.style.display = 'none';
try {
const data = await apiCall('/memory/consolidate', 'POST');
if (data.success) {
status.textContent = ' Consolidation complete!';
status.style.color = '#6fdc6f';
resultDiv.textContent = data.result || 'Consolidation finished successfully.';
resultDiv.style.display = 'block';
showNotification('Memory consolidation complete', 'success');
refreshMemoryStats();
status.textContent = ' Consolidation started — waiting for completion...';
// Poll /memory/status until consolidation finishes
const pollInterval = 5000; // 5 seconds
const maxPolls = 120; // 10 minutes max
for (let i = 0; i < maxPolls; i++) {
await new Promise(r => setTimeout(r, pollInterval));
const statusData = await apiCall('/memory/status');
const cons = statusData.consolidation;
if (!cons.is_running) {
// Consolidation finished
if (cons.last_error) {
status.textContent = '❌ ' + cons.last_error;
status.style.color = '#ff6b6b';
resultDiv.textContent = 'Error: ' + cons.last_error;
resultDiv.style.display = 'block';
showNotification('Consolidation failed: ' + cons.last_error, 'error');
} else {
status.textContent = '✅ Consolidation complete!';
status.style.color = '#6fdc6f';
resultDiv.textContent = cons.last_result || 'Consolidation finished successfully.';
resultDiv.style.display = 'block';
showNotification('Memory consolidation complete', 'success');
}
refreshMemoryStats();
break;
} else {
// Still running — update status message
status.textContent = `⏳ Consolidation still running... (${Math.round((i + 1) * pollInterval / 1000)}s elapsed)`;
}
}
// If we exited the loop without finishing
const finalStatus = await apiCall('/memory/status');
if (finalStatus.consolidation?.is_running) {
status.textContent = '⏳ Consolidation still running — check back later';
status.style.color = '#dcb06f';
}
} else {
status.textContent = '❌ ' + (data.error || 'Consolidation failed');
status.style.color = '#ff6b6b';