personal memory agent
0
fork

Configure Feed

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

convey/chat: source recovered talent location from owner_message

Revert the sol_message app/path/facet extension and track the latest
owner_message alongside the latest sol_message during the recovery
walk. owner_message already carries location per the chat_stream
schema; extending sol_message was unnecessary. Also dedupe the
pulse-needs-item branching in the dashboard click/keydown handlers
into a single dispatchConversationElement helper.

Co-Authored-By: OpenAI Codex <codex@openai.com>

+32 -29
+13 -16
apps/home/workspace.html
··· 1424 1424 // Click-to-converse: delegated handler for all [data-conversation] elements 1425 1425 var dashboard = document.querySelector('.pulse-dashboard'); 1426 1426 if (dashboard) { 1427 + function dispatchConversationElement(el) { 1428 + if (el.closest('[data-routine-click]') || el.hasAttribute('data-routine-click')) { 1429 + fetch('/app/home/api/routines/seen', {method: 'POST'}); 1430 + } 1431 + if (el.classList.contains('pulse-needs-item')) { 1432 + window.suggestChat(el.dataset.conversation); 1433 + } else { 1434 + window.fillChat(el.dataset.conversation); 1435 + } 1436 + } 1437 + 1427 1438 dashboard.addEventListener('click', function(e) { 1428 1439 // Skill inline expansion 1429 1440 var skillEl = e.target.closest('[data-skill-click]'); ··· 1436 1447 var el = e.target.closest('[data-conversation]'); 1437 1448 if (el) { 1438 1449 e.preventDefault(); 1439 - if (el.closest('[data-routine-click]') || el.hasAttribute('data-routine-click')) { 1440 - fetch('/app/home/api/routines/seen', {method: 'POST'}); 1441 - } 1442 - if (el.classList.contains('pulse-needs-item')) { 1443 - window.suggestChat(el.dataset.conversation); 1444 - } else { 1445 - window.fillChat(el.dataset.conversation); 1446 - } 1450 + dispatchConversationElement(el); 1447 1451 } 1448 1452 }); 1449 1453 dashboard.addEventListener('keydown', function(e) { ··· 1464 1468 var el = e.target.closest('[data-conversation]'); 1465 1469 if (el) { 1466 1470 e.preventDefault(); 1467 - if (el.closest('[data-routine-click]') || el.hasAttribute('data-routine-click')) { 1468 - fetch('/app/home/api/routines/seen', {method: 'POST'}); 1469 - } 1470 - if (el.classList.contains('pulse-needs-item')) { 1471 - window.suggestChat(el.dataset.conversation); 1472 - } else { 1473 - window.fillChat(el.dataset.conversation); 1474 - } 1471 + dispatchConversationElement(el); 1475 1472 } 1476 1473 }); 1477 1474 }
+10 -9
convey/chat.py
··· 307 307 notes=parsed["notes"], 308 308 requested_target=requested_target, 309 309 requested_task=requested_task, 310 - app=_current_chat_state["location"]["app"], 311 - path=_current_chat_state["location"]["path"], 312 - facet=_current_chat_state["location"]["facet"], 313 310 ) 314 311 _current_chat_state["retry_count"] = 0 315 312 _set_current_raw_use_locked(logical_use_id, None) ··· 598 595 599 596 def _recover_active_talents_locked(day: str) -> None: 600 597 events = read_chat_events(day) 598 + latest_owner_message: dict[str, Any] | None = None 601 599 latest_sol_message: dict[str, Any] | None = None 602 600 spawned: dict[str, dict[str, Any]] = {} 603 601 604 602 for event in events: 605 603 kind = event.get("kind") 604 + if kind == "owner_message": 605 + latest_owner_message = event 606 + continue 606 607 if kind == "sol_message": 607 608 latest_sol_message = event 608 609 continue ··· 610 611 use_id = str(event.get("use_id") or "") 611 612 if not use_id: 612 613 continue 613 - if latest_sol_message is None: 614 + if latest_sol_message is None or latest_owner_message is None: 614 615 logger.warning( 615 - "skipping active-talent recovery for %s: no parent sol_message", 616 + "skipping active-talent recovery for %s: no parent chat turn", 616 617 use_id, 617 618 ) 618 619 continue 619 620 chat_use_id = str(latest_sol_message.get("use_id") or "") 620 621 if not chat_use_id: 621 622 logger.warning( 622 - "skipping active-talent recovery for %s: no parent sol_message", 623 + "skipping active-talent recovery for %s: sol_message missing use_id", 623 624 use_id, 624 625 ) 625 626 continue ··· 628 629 "target": str(event.get("name") or ""), 629 630 "task": str(event.get("task") or ""), 630 631 "location": _normalize_location( 631 - latest_sol_message.get("app"), 632 - latest_sol_message.get("path"), 633 - latest_sol_message.get("facet"), 632 + latest_owner_message.get("app"), 633 + latest_owner_message.get("path"), 634 + latest_owner_message.get("facet"), 634 635 ), 635 636 } 636 637 continue
+9 -4
tests/test_chat_runtime.py
··· 74 74 now = datetime.now() 75 75 start = _ms(now.year, now.month, now.day, 12, 0, 0) 76 76 append_chat_event( 77 + "owner_message", 78 + ts=start, 79 + text="Help me with this", 80 + app="home", 81 + path="/app/home", 82 + facet="work", 83 + ) 84 + append_chat_event( 77 85 "sol_message", 78 - ts=start, 86 + ts=start + 1, 79 87 use_id=chat_use_id, 80 88 text="I am looking into that.", 81 89 notes="need exec", 82 90 requested_target=target, 83 91 requested_task=task, 84 - app="home", 85 - path="/app/home", 86 - facet="work", 87 92 ) 88 93 append_chat_event( 89 94 "talent_spawned",