Skip to content

Refactor Fathom: fact-centric research, embedding ranking, source memory#90

Merged
Okm165 merged 52 commits into
feat/shared-module-refactorfrom
feat/fathom-service-refactor
Jun 10, 2026
Merged

Refactor Fathom: fact-centric research, embedding ranking, source memory#90
Okm165 merged 52 commits into
feat/shared-module-refactorfrom
feat/fathom-service-refactor

Conversation

@Okm165

@Okm165 Okm165 commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • Align config with shared InfraSettings, async caller with concurrency gates
  • Evolve domain models from document synthesis to fact-centric research
  • Replace LLM URL scoring with embedding RRF ranking + softmax sampling
  • Add cross-session source memory via Qdrant + Neo4j graph
  • Two-tier fetch: preview batch for gating, then selective full fetch
  • Rewrite research loop with depth presets, timeout, source memory, ranked context
  • Refactor API for real-time SSE, health probes, bounded concurrency
  • Remove CLI, dashboard, provider, selection modules (5 files deleted)

Test plan

  • Research session completes with structured facts output
  • Source memory persists across sessions
  • Preview fetch correctly gates full extraction
  • SSE stream delivers real-time progress events

Okm165 added 30 commits June 10, 2026 15:20
Inherit InfraSettings to eliminate duplicated infra fields. Add
browser_concurrency, sample_temperature, qdrant_search_ef,
exploration_divergence, session_timeout. Set llm_max_tokens=-1,
llm_request_timeout=3600.
Module-level provider via settings.make_llm_provider(). Add async
concurrency gates. Introduce async_llm_call, format_prompt,
async_embed_query, async_embed_documents via make_gated_embedders.
Provider creation inlined into caller via InfraSettings factory.
CLI entry point and Rich ResearchDashboard removed — Fathom is
API-only. Delete __main__.py, cli.py, observe.py, provider.py.
Remove URLScoring, Contradiction, ResearchOutput, WebSearch/WebExtract
types. Replace has_evidence boolean with source_quality float. Add
DomainStats, extract_domain(), FactWithSource. Add depth presets
(glance through exhaustive). Field validation with clamping.
Remove document from ResearchSession, add timed_out status. Add
source_quality on ResearchFact. Batch add_urls/insert_facts/
save_checklist with UNWIND Cypher. Randomize pending URL order.
Add SourceDomain/TopicCluster graph nodes. Add cleanup_stale_sessions
and check() health probe.
Remove SCORE_URLS, UPDATE_CHECKLIST, COMPRESS_KNOWLEDGE, WRITE_SECTION,
WRITE_INTRO_CONCLUSION prompts. Rewrite decomposition for search-query-
friendly questions and page analysis for source_quality. LLM surface
reduced to decompose_goal, generate_queries, analyze_page only.
Introduce rank_urls_hybrid() with RRF fusion of embedding similarity
and session domain quality, softmax-temperature sampling. Add
build_ranked_knowledge_context() for page analysis. Delete LLM-based
selection.py (probabilistic_sample, format_urls_for_scoring).
Qdrant fathom_sources collection for persistent source intelligence.
record_source() upserts embedding and updates SourceDomain/TopicCluster
graph. suggest_sources() ranks by vector similarity weighted by domain
quality. diverge_probabilistically() blends goal and known-URL centroid.
Browser: add check() health probe and fetch_preview_batch() for
lightweight domcontentloaded previews. Extract: add extract_preview()
with metadata/headings/lead text for quality signal before full fetch.
Search: add 30s timeout on DuckDuckGo calls. Remove single-URL fetch().
Replace document synthesis with fact-gathering engine. Add 7 depth
presets. Session timeout enforcement. Source memory integration.
Embedding ranking pool with preview-then-select pipeline. HTML cache
reuse. Ranked knowledge context for page analysis. Rich SSE via _emit.
Remove stall detection, checklist answering, contradiction pipeline,
document writing, dashboard parameter.
Add Qdrant lifecycle, stale session cleanup, RequestIDMiddleware,
shared HealthResponse with Neo4j/Qdrant/browserless/LLM probes.
Concurrency cap (2 sessions, HTTP 429). Per-session asyncio.Queue
for real-time SSE. Return facts list instead of document. Remove
/search and /extract endpoints. Clean __init__.py logging side effect.
Inherit shared InfraSettings to eliminate duplicated infra fields.
Add ingest_temperature, max_stalls, max_extends, context_char_limit.
Scale chat_input_token_budget to 150K, llm_timeout to 3600. Remove
agent_compress_threshold/keep_tail, ess_timeout, web_search_enabled.
Module-level provider via settings.make_llm_provider(). Add async
concurrency gates, format_prompt, async_llm_call, gated embedding
entry points. Remove consensus_call. Delete provider.py (interaction
gating, module-level default_provider).
Add normalize_topic() for canonical topic slugs. Add Phase enum for
agent automaton. Add EventType.TOOL_PROGRESS. Replace QDRANT_COLLECTIONS
constant with qdrant_collection_specs(dims) factory. Add prospective
query and credibility signal floats to derivative payload. Remove
Neo4j Derivative/Segment/Summary constraints. Reduce tool names to
recall_memory, web_research, integrate_knowledge.
Introduce CredibilitySignals dataclass with five continuous 0-1
dimensions replacing ReasoningType, SourceReliability, OpinionDirection,
KnowledgeDensity. Continuous float urgency replaces UrgencyLevel enum.
Add existing_topics for dedup. Pydantic bounds on schema fields.
Add identity/confidentiality system instructions and cognitive
discipline. Add CONSOLIDATION_INSTRUCTIONS for working-memory JSON
replacing handoff/compression prompts. Rewrite ESS prompt for
continuous credibility dimensions. Add WEB_EVIDENCE_HEADER,
PROSPECTIVE_QUERY_PROMPT, build_ingest_system(). Remove LOOP_HANDOFF,
STATE_COMPRESSION, BOUNDARY_DETECTION, SUFFICIENCY, DECOMPOSITION,
CONSOLIDATION_READINESS/SUMMARY, SYNTHESIZE prompts. Rewrite belief
prompts for bears_on_belief gate and signal weights.
Add _DEFAULT_COMPLETION_RESERVE (16K). Raise SUMMARIZE_THRESHOLD 8->20
and per-message slice 300->800 chars. Use format_prompt() and
instructions= API. Add Field(max_length) on summary schema. Use
render_labeled(). Remove multipart message content handling.
CLI: import ChatRole from shared.types, use structlog.get_logger.
Progress: remove re-exported event constants (callers use EventType
from schema directly).
Remove Derivative, Segment, Summary nodes and all related edges.
Add five credibility signal fields to EpisodeNode. MERGE-based
store_episode and link_belief with evidence count recomputation.
FSRS power-law utility scoring. Rewire TEMPORAL_NEXT on delete.
Add get_topic_names() and get_belief_connections(). Batch topic
linking with normalize_topic.
Store: accept ESSResult with credibility signals. Qdrant Prefetch +
FormulaQuery with per-signal additive boosts. Add prospective queries
for ROXY-style vocabulary bridging. Add remove_knowledge_citations()
for forgetting cascade. DB: accept optional embedding_dims, guard
partial init on close.
Convert chunk_and_embed() to async using async_llm_call and
async_embed_documents. Switch from local EmbedderProtocol to
shared.embedder.Embedder. Add _MAX_CHUNKS=15 validation. Delete
memory/embedder.py (FastEmbed wrapper consolidated into shared).
Introduce EpisodeEvidence dataclass bundling episode context, ESS
score, and CredibilitySignals. Add _belief_snapshot() for prompt
serialization. Create provenance edges only when bears_on_belief is
true and evidence_strength > 0. Migrate to async_llm_call. Batch
cap 30, normalize_topic.
Block FORGET when episode is sole evidence for a belief via
get_belief_connections(). Call remove_knowledge_citations() on ARCHIVE
and FORGET. Log but do not re-raise on Qdrant failure after graph
delete. Async LLM with 50 decision validation cap.
Remove PropositionType enum, negation handling, type-based filtering,
and confidence inflation. Citation accumulation only with MAX_CITATIONS
cap. Async _split_windows and _extract_propositions. Use
VECTOR_SEARCH_THRESHOLD. UID seed from full normalized text.
Delete EventBoundaryDetector, LLM boundary detection, segment counter
persistence. Delete LLM-based segment readiness check and HEMA
hierarchical summary generation. Graph Segment/Summary nodes already
removed.
Router: add SearchPass with optional query rewrite and signal_weights.
_sanitize_weights() clamps to ESS signal names (max 0.3, max 3 passes).
Remove QueryCategory.MULTI_ENTITY and should_decompose. Async
route_query(). Reranker: async with ESS/quality in episode lines.
Overflow candidates appended after ranked portion.
New retrieve() single orchestrator: route -> multi-pass fetch (graph
topic/belief hits + per-pass vector search with signal weights) ->
temporal expand -> rerank -> access update -> optional semantic feature
search -> formatted context strings. Delete chain.py (iterative
sufficiency loop) and split.py (LLM decomposition). Export retrieve.
Rename SemanticIngestionWorker to SemanticFeatureExtractor. Replace
background thread/queue/event loop with direct async process_episode().
Lazy consolidation at CONSOLIDATION_THRESHOLD=20. Injected
AsyncQdrantClient. Per (tag, feature) dedup with citation merge and
re-embedding.
Export EpisodeEvidence, SemanticFeatureExtractor, retrieve. Remove
Embedder, StoredEpisode, BoundaryDecision, EventBoundaryDetector,
SemanticIngestionWorker, chain_retrieve, split_retrieve.
Pure data models and stateless helpers: MemoryUpdate (LTM/STM
consolidation schema), LoopStep, ActingContext, LoopState (per-request
mutable state). build_step_context(), build_scaffolding(),
synthesis_prompt(), dedup_tool_calls(), summarize_for_step_log(). No IO.
Okm165 added 22 commits June 10, 2026 15:24
BookkeepingItem queue payload. classify_ess() with topic normalization
and existing graph topics context. enqueue_bookkeeping() thread-safe
non-blocking put. process_bookkeeping() consumer: store episode then
shared pipeline. post_ingest() synchronous ingest path. _run_pipeline:
provenance -> semantic features -> knowledge extraction -> forgetting.
Replace SearchResult/ExtractResult with ResearchFact (claim + confidence
+ source metadata). Add ResearchProgress with SSE event mapping. Multi-
line SSE data buffering with terminal events. Trace propagation via
X-Trace-ID. Parse facts from API instead of document. Remove search()/
multi_search()/extract(). 5h read timeout.
Add ProgressCallback and _noop_progress. Extend ToolContext with
research_transcript callable, short_term_memory, progress callback.
Add ToolLabeler registry and tool_label() for UI/SSE display. Remove
build_research_transcript() and synthesize from lazy loader. Import
Embedder from shared.
Replace web_search and web_extract with unified web_research at all
depth presets (glance through exhaustive). Add ResearchArgs and
parse_research_args(). merge_facts() dedupes streamed vs final.
format_facts() groups by source with confidence tags. Progress via
ctx.progress(). STM injected into research goal. HTTP 429 handling.
Delete evidence synthesis tool. Research now returns structured
facts — agent reasons over facts and calls integrate_knowledge.
Add ctx.progress() at recall/integrate stages. Deterministic episode
identity via deterministic_id. Partial-store degradation messages.
Add ctx.short_term_memory in recall output. Use ctx.research_transcript
for reflect. Richer section headers with counts.
Replace LLM-based belief reranking with rank_beliefs_by_similarity
(embedding cosine) and rank_beliefs_algorithmically (RRF fusion of
embedding + graph confidence * log evidence). Single reasoning model
LLM call. Web enrichment via start_research depth=glance. Remove
consensus_call, _merge_reflections, forgetting cycle.
Use shared RequestIDMiddleware, HealthResponse, check_health_
dependencies. Constant-time bearer token auth via hmac.compare_digest.
Stream wrapped in try/except yielding SSE error event. Max tokens
upper bound 131072. Remove /chat endpoint. Ingest response:
CredibilitySignals dict + float urgency. Pydantic range constraints
on belief fields.
LoopState per-request instead of instance fields. THINKING/ACTING
phase machine: _phase_thinking (LLM + compose_guarded, stall/extend
handling), _phase_acting (dispatch + MemoryUpdate consolidation, raw
tool output never re-enters THINKING). Async bookkeeping queue.
_pre_seed_memory for episodic LTM retrieval. _flush_ltm_to_episode.
_rank_beliefs with embedding cosine. Streaming Fathom research via
thread-safe queue. check_dependencies health probe. Shutdown drain
with 10s timeout. Remove context folding, message compression, loop
handoff, boundary detection, segment consolidation.
Config: add tts_optimize_concurrency, pydantic validator for TTS
fallback defaults, set tts_optimize_max_tokens to -1, default log
level DEBUG. Package init: entry-point only, logging from settings.
Replace local llm_call wrapper with compose_guarded() + provider
chat_completion. LLMProvider gets concurrency from settings. _TTS_SYSTEM
as Final system prompt. Context char limit derived from max_tokens.
Per-request trace_id with X-Trace-ID header and structlog binding.
Rename web_search/web_extract tool labels to web_research. Add goal
to arg summary scan. Harden SSE parsing with safe empty choices. Fix
empty assistant response history corruption. Add tool_progress logging.
Add tool_progress handling with intermediate status updates. Scrolling
status window (last 8 steps, max 10 lines). Remove reviewing progress,
ESS score/reasoning_type/topics from done footer. Structured elapsed_s.
Stdlib-only HuggingFace GGUF downloader. Default output to .models/.
Models: llm (Qwen3.6-35B Q4_K_XL), embed (Qwen3-Embedding-4B Q4_K_M).
Selective --all, --list, --force flags. Resumable downloads with .part
files. Optional --verify SHA-256.
Feed: strip HTML tags from article description before MIN_DESC_LEN
check. Diagnostics: migrate config access to pydantic settings API,
remove neo4j_derivatives count and derivative density health rules.
Delete tests/containers.py (Qdrant/Neo4j testcontainers lifecycle).
Remove --use-containers option, session db_containers fixture, autouse
clear_db_between_tests, multi-target mock_llm_call fixture. Add minimal
env defaults. Root conftest: drop benches scope, suppress_expected_logs.
Regression tests for clean_completion, decode_llm_json,
extract_tool_calls, strip_markdown, message_content_text,
normalize_llm_list_response, coerce_string_fields.
Fathom: remove URLScoring tests, split PageAnalysisResult tests for
dict and bare list input. Derivatives: patch async_llm_call and
async_embed_documents with AsyncMock. API: update _make_ess() for
CredibilitySignals + float urgency, mock check_dependencies and
http_dependency_status.
Update chat clients, scripts, and test suite
Rewrite Sonality agent: two-phase automaton, unified tools, async bookkeeping
Refactor Sonality memory: graph schema, ESS storage, unified retrieval
Refactor Sonality core: config, ESS signals, prompts, caller
@Okm165
Okm165 merged commit 98b9385 into feat/shared-module-refactor Jun 10, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant