Navigácia
ELOWEN · Dokumentácia

Posledná aktualizácia: 20. októbra 2026

Prechádzať dokumentáciu · Conversation search

Tento článok zatiaľ nie je preložený. Je dostupný v angličtine.

Developer reference

Conversation search

The web reads message hits through GET /brain/search: the personal conversation list's search and the conversation diagnostics register. The route resolves the caller's read scope and calls BrainService.searchMessages, which delegates through BrainStatusService to await repositories.search.searchMessages(userId, query, limit); an administrator may pass scope=instance, which searches every account's conversations instead of only the caller's. The PostgreSQL search repository in packages/db/src/search/index.ts owns the query; BrainSearchHit is exported by elowen-db. A query that trims to fewer than two UTF-16 code units, or a nonpositive limit, returns no hits before any query.

Storage and ownership

brain_session_entries retains the original text and identity. brain_search_rows contains the canonical shown message text, keyed by (session_id, seq), with a pg_trgm GIN index. PostgreSQL extensions and indexes are installed by the numbered baseline migration.

Journal mutations call the search owner's refreshJournalSearch on their bound transaction. Append, rewrite, rekey, restore and physical removal update the derived rows together with the authoritative journal. Text is decoded from original JSON in TypeScript; embedded NUL becomes U+FFFD only in the derived projection. The original payload and hashes remain unchanged.

The projection covers shown user and assistant text from every journal, personal and channel alike. Meta messages, discarded entries and tool results are excluded. A read applies the shared empty-conversation visibility predicate (emptyShell) and accepts only completed fork copies; an account-scoped read additionally checks session ownership and leaves channel sessions out. An instance-scoped read also considers channel rows that have no projected row, matching their raw journal JSON, because historical channel journals can predate the projection. The index supplies candidates and grants no access.

Read contract and cost

Queries containing at least three Unicode code points and no NUL use escaped literal ILIKE against projected text. Shorter queries and queries with NUL, which the trigram representation cannot serve, use escaped raw JSON candidates. The projection has no readiness state: migration 0002_drop_projection_backfill_state.sql dropped the import-era brain_search_backfill gate, because every journal write maintains the rows. Percent signs, underscores and backslashes remain literal input.

The reader pages at most 500 native candidates at a time using the exact (created_at, row_id) cursor and caps accepted raw matches at 500. TypeScript preserves the established ASCII-folded raw JSON match, then extracts shown text, validates active-branch membership and produces the existing 60-character snippet radius. Results are newest first. A root read uses one read-only repeatable-read snapshot, so candidate selection and branch checks describe the same committed state.

packages/db/tests/search/brainSearchIndex.test.ts covers projection maintenance, literal matching and journal mutations. packages/db/tests/transcript/journalBranch.test.ts covers branch authority. PostgreSQL behavior and measured limits are also described in Persistence.