personal memory agent
0
fork

Configure Feed

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

chat: index chat events incrementally on write

append_chat_event now triggers index_file on the segment chat.jsonl after
the write lock is released and before the callosum broadcast. Chat events
become searchable through /app/search immediately, without requiring a
sol indexer --rescan.

Indexer exceptions are logged as warnings (exc_info=True) and never
re-raised, so transient index failures cannot break chat writes. The
indexer is already idempotent on re-run.

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

+56
+13
convey/chat_stream.py
··· 14 14 from typing import Any 15 15 16 16 from think.callosum import callosum_send 17 + from think.indexer.journal import index_file 17 18 from think.streams import update_stream, write_segment_stream 18 19 from think.utils import day_path, get_journal, segment_key, segment_parse, segment_path 19 20 ··· 73 74 stream_info["seq"], 74 75 ) 75 76 77 + try: 78 + index_file(get_journal(), str(chat_path)) 79 + except Exception: 80 + logger.warning( 81 + "chat-event-index-failed", 82 + extra={ 83 + "kind": kind, 84 + "use_id": str(stored_event.get("use_id") or ""), 85 + "chat_path": str(chat_path), 86 + }, 87 + exc_info=True, 88 + ) 76 89 _broadcast_chat_event(stored_event) 77 90 return stored_event 78 91
+43
tests/test_chat_stream_indexing.py
··· 1 + # SPDX-License-Identifier: AGPL-3.0-only 2 + # Copyright (c) 2026 sol pbc 3 + 4 + 5 + def test_append_chat_event_indexes_without_rescan(tmp_path, monkeypatch): 6 + from convey.chat_stream import append_chat_event 7 + from think.indexer.journal import search_journal 8 + 9 + monkeypatch.setenv("_SOLSTONE_JOURNAL_OVERRIDE", str(tmp_path)) 10 + 11 + total, results = search_journal("nebula phrase X42", stream="chat") 12 + assert total == 0 13 + assert results == [] 14 + 15 + append_chat_event( 16 + "owner_message", 17 + text="unique nebula phrase X42", 18 + app="sol", 19 + path="/app/sol", 20 + facet="work", 21 + ) 22 + 23 + total, results = search_journal("nebula phrase X42", stream="chat") 24 + assert total == 1 25 + assert any("nebula phrase x42" in result["text"].lower() for result in results) 26 + assert {result["metadata"]["stream"] for result in results} == {"chat"} 27 + 28 + append_chat_event( 29 + "owner_message", 30 + text="second unique aurora signal Y99", 31 + app="sol", 32 + path="/app/sol", 33 + facet="work", 34 + ) 35 + 36 + total, results = search_journal("aurora signal Y99", stream="chat") 37 + assert total == 1 38 + assert any("aurora signal y99" in result["text"].lower() for result in results) 39 + assert {result["metadata"]["stream"] for result in results} == {"chat"} 40 + 41 + total, results = search_journal("nebula phrase X42", stream="chat") 42 + assert total == 1 43 + assert any("nebula phrase x42" in result["text"].lower() for result in results)