personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

convey/entities: migrate delete + generate-description to wave 0 primitives (wave 2)

Route the description-generation kickoff, delete preview, and delete confirm flows through apiJson. Preserve the existing inline error surfaces while removing the optimistic delete path.

+45 -39
+45 -39
apps/entities/workspace.html
··· 2412 2412 }; 2413 2413 2414 2414 generateBtn.onclick = () => { 2415 + hideInlineError('description-save-error'); 2415 2416 textarea.disabled = true; 2416 2417 generateBtn.classList.add('generating'); 2417 2418 2418 - fetch(`api/${encodeURIComponent(currentFacet)}/generate-description`, { 2419 + window.apiJson(`api/${encodeURIComponent(currentFacet)}/generate-description`, { 2419 2420 method: 'POST', 2420 2421 headers: { 'Content-Type': 'application/json' }, 2421 2422 body: JSON.stringify({ ··· 2424 2425 current_description: textarea.value 2425 2426 }) 2426 2427 }) 2427 - .then(response => response.json()) 2428 2428 .then(data => { 2429 - if (data.success && data.use_id) { 2430 - listenForAgentCompletion(data.use_id, (result) => { 2431 - if (result.success && result.response) { 2432 - saveDescription(entity, result.response); 2433 - } else { 2434 - textarea.disabled = false; 2435 - generateBtn.classList.remove('generating'); 2436 - } 2429 + if (!data?.use_id) { 2430 + throw new window.ApiError({ 2431 + cause: 'parse', 2432 + status: 200, 2433 + serverMessage: 'Malformed server response', 2434 + url: `api/${encodeURIComponent(currentFacet)}/generate-description` 2437 2435 }); 2438 - } else { 2439 - throw new Error(data.error || 'Failed to start generation'); 2440 2436 } 2437 + 2438 + listenForAgentCompletion(data.use_id, (result) => { 2439 + if (result.success && result.response) { 2440 + saveDescription(entity, result.response); 2441 + } else { 2442 + textarea.disabled = false; 2443 + generateBtn.classList.remove('generating'); 2444 + showInlineError('description-save-error', result.error || "Couldn't start description generation"); 2445 + } 2446 + }); 2441 2447 }) 2442 - .catch(error => { 2443 - console.error('Error generating description:', error); 2448 + .catch(err => { 2444 2449 textarea.disabled = false; 2445 2450 generateBtn.classList.remove('generating'); 2451 + showInlineError('description-save-error', err?.serverMessage || "Couldn't start description generation"); 2452 + window.logError(err, { context: 'entities: generateDescription kickoff failed' }); 2446 2453 }); 2447 2454 }; 2448 2455 } ··· 3398 3405 3399 3406 // Delete detected entity 3400 3407 function previewEntityDelete(entityName) { 3401 - fetch(`api/${encodeURIComponent(currentFacet)}/detected/preview?name=${encodeURIComponent(entityName)}`) 3402 - .then(response => response.json()) 3408 + window.apiJson(`api/${encodeURIComponent(currentFacet)}/detected/preview?name=${encodeURIComponent(entityName)}`) 3403 3409 .then(data => { 3404 3410 if (data.success && data.days) { 3405 3411 hideInlineError('detected-action-error'); ··· 3421 3427 modal.style.display = 'flex'; 3422 3428 } 3423 3429 }) 3424 - .catch(error => { 3425 - console.error('Error previewing delete:', error); 3426 - showInlineError('detected-action-error', "couldn't load delete preview"); 3430 + .catch(err => { 3431 + showInlineError('detected-action-error', err?.serverMessage || "Couldn't load delete preview"); 3432 + window.logError(err, { context: 'entities: previewEntityDelete failed' }); 3427 3433 }); 3428 3434 } 3429 3435 ··· 3431 3437 document.getElementById('deleteModal').style.display = 'none'; 3432 3438 } 3433 3439 3434 - function deleteEntity(entityName, skipReload = false) { 3435 - return fetch(`api/${encodeURIComponent(currentFacet)}/detected`, { 3436 - method: 'DELETE', 3437 - headers: { 'Content-Type': 'application/json' }, 3438 - body: JSON.stringify({ name: entityName }) 3439 - }) 3440 - .then(response => response.json()) 3441 - .then(data => { 3442 - if (!data.success) throw new Error(data.error); 3443 - if (!skipReload) loadEntities(); 3444 - }); 3445 - } 3446 - 3447 3440 function removeEntityFromUI(entityName) { 3448 3441 if (entitiesData && entitiesData.detected) { 3449 3442 entitiesData.detected = entitiesData.detected.filter(e => e.name !== entityName); ··· 3451 3444 renderDetectedTable(document.getElementById('entity-search').value.trim()); 3452 3445 } 3453 3446 3454 - function confirmEntityDelete() { 3447 + async function confirmEntityDelete() { 3455 3448 const entityName = document.getElementById('confirmDeleteBtn').dataset.entityName; 3456 3449 if (!entityName) return; 3457 3450 3458 - closeDeleteModal(); 3459 - removeEntityFromUI(entityName); 3460 - deleteEntity(entityName, true).catch(error => { 3461 - console.error('Error deleting:', error); 3462 - loadEntities(); 3463 - }); 3451 + const confirmBtn = document.getElementById('confirmDeleteBtn'); 3452 + confirmBtn.disabled = true; 3453 + 3454 + try { 3455 + await window.apiJson(`api/${encodeURIComponent(currentFacet)}/detected`, { 3456 + method: 'DELETE', 3457 + headers: { 'Content-Type': 'application/json' }, 3458 + body: JSON.stringify({ name: entityName }) 3459 + }); 3460 + hideInlineError('detected-action-error'); 3461 + closeDeleteModal(); 3462 + removeEntityFromUI(entityName); 3463 + } catch (err) { 3464 + closeDeleteModal(); 3465 + showInlineError('detected-action-error', err?.serverMessage || "Couldn't delete entity"); 3466 + window.logError(err, { context: 'entities: confirmEntityDelete failed' }); 3467 + } finally { 3468 + confirmBtn.disabled = false; 3469 + } 3464 3470 } 3465 3471 </script>