* feat(memory): LLM-based NER + importance signal with cheap-signals short-circuit (#708) Adds an Ollama-backed entity extractor and an LLM-derived importance score as a new signal in the admission gate. Builds on merged Phase 2 (#733) without changing its surface — additive only. Why LLM (not GLiNER): zero new deps (reuses existing reqwest + async infra), reuses the same Ollama setup openhuman uses for embeddings, better per-entity quality scales with model choice, no native ONNX runtime to ship. Latency cost (~100-300ms per chunk on a small model like qwen2.5:0.5b) is amortised by the short-circuit. The admission gate stays a hybrid - cheap deterministic signals always run; the LLM is one signal among many, never the sole arbiter. Backwards-compatible: with default SignalWeights the LLM weight is 0.0 and behaviour matches pre-LLM Phase 2 exactly. What's new: - src/openhuman/memory/tree/score/extract/llm.rs: LlmEntityExtractor implementing the existing EntityExtractor trait. Posts a structured JSON request to an Ollama-compatible /api/chat endpoint asking for NER + an importance rating in one call. Span recovery via string search; hallucinated entities (surface not in source text) dropped. Soft fallback: HTTP failures log a warn and return empty extraction. - ExtractedEntities gains llm_importance (Option<f32>) + llm_importance_reason (Option<String>); merge() takes max importance. - ScoreSignals gains llm_importance (f32, defaults to 0.0). - SignalWeights gains llm_importance (default 0.0; with_llm_enabled() helper sets it to 2.0 - comparable to metadata/source weights). - signals::combine_cheap_only(): variant that excludes the LLM signal, used for the short-circuit decision in score_chunk. - ScoringConfig gains llm_extractor (Option<Arc<dyn EntityExtractor>>), definite_keep_threshold (default 0.85), definite_drop_threshold (default 0.15). New with_llm_extractor() constructor. - score_chunk() pipeline: 1. Always-on regex extraction 2. Cheap signals + combine_cheap_only -> cheap_total 3. If cheap_total >= definite_keep OR <= definite_drop: skip LLM 4. Else (borderline band): run LLM extractor, merge results, recompute 5. Final combine + admission gate against drop_threshold - mem_tree_score table gains nullable llm_importance + llm_importance_reason columns via idempotent ALTER TABLE migration. - ScoreRow + upsert/get persist the new column. What's not changed: - Existing JSON-RPC surface - Default behaviour (LLM weight=0, no llm_extractor configured = same outputs as before) - mem_tree_chunks / mem_tree_entity_index schemas Tests added: - LLM extractor: prompt construction, JSON parsing, hallucination drop, importance clamping, strict vs lenient unknown-kind handling - Score pipeline: short-circuit on definite_keep/definite_drop skips LLM call (verified via FakeLlm call counter); borderline band consults LLM once; LLM failure falls back gracefully without erroring LLM-NER work follows up on #708. Parent: #711. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(memory): address CI failures and CodeRabbit review on LLM-NER (#708) CI was red on PR #775 due to 10 E0063 errors — existing test-only struct literals for ExtractedEntities / ScoreSignals / ScoreRow weren't updated when the new optional llm_importance fields landed. Local cargo check on lib-only passed; cargo check --tests caught them, as does CI. CodeRabbit also flagged four semantic issues: 1. LlmEntityExtractor::extract() returned Err on HTTP transport, non-2xx status, and JSON parse failures. The soft-fallback contract (documented in the module header) only worked because score_chunk catches errors; any other caller got a hard error. Now split into extract_or_empty() which logs a warn on each failure mode and returns ExtractedEntities::default() unconditionally. The public extract() stays on the async-trait surface but never returns Err. 2. find_char_span() always searched from byte offset 0, so when the LLM returned the same surface twice (explicitly asked for duplicates in the prompt), both entities got (start=0, end=len) — same span, not distinct mentions. Added find_char_span_from(haystack, needle, byte_from, char_from) that resumes from a cursor. into_extracted_entities now tracks a per-surface (byte_after, char_after) cursor in a HashMap<String, (usize, u32)>, so duplicate mentions get distinct non-overlapping spans and over-claim (LLM returns 3 "Alice" when source has 2) drops the excess entries with a debug log. 3. combine() always included w.llm_importance in the denominator even when llm_importance=0.0 because the LLM didn't run. That artificially lowered the total on short-circuit paths. score_chunk now branches on llm_consulted: uses combine() when LLM ran (importance actually contributes), combine_cheap_only() when LLM was skipped or failed (denominator excludes the LLM weight). Observable in two new tests: short_circuit_reports_cheap_only_total verifies r.total == combine_cheap_only(r.signals, weights) and strictly exceeds combine(r.signals, weights) when llm_importance=0; llm_consulted_ reports_full_total verifies the opposite path. 4. Same issue from a different angle (CodeRabbit flagged both). Fixed by the same llm_consulted branch. Test-literal fixes: - signals/ops.rs: ScoreSignals literals pick up llm_importance field; make_entities helper uses ..Default::default() on ExtractedEntities. - extract/types.rs: three test ExtractedEntities literals gain llm_importance: None, llm_importance_reason: None. - resolver.rs: canonicalise_batch_preserves_spans literal gains the two fields. - score/store.rs: sample_row gains signals.llm_importance and llm_importance_reason. New tests (7 added): - find_char_span_from_advances_past_prior_match - find_char_span_from_returns_none_after_exhaustion - find_char_span_from_preserves_utf8 - find_char_span_from_rejects_non_char_boundary - into_extracted_entities_gives_distinct_spans_to_duplicate_mentions - into_extracted_entities_drops_extra_duplicate_when_source_only_has_one - extract_soft_fallback_on_unreachable_endpoint (transport failure → empty extraction, not Err) - short_circuit_reports_cheap_only_total - llm_consulted_reports_full_total cargo check --lib clean; cargo fmt clean. The integration-test rmeta errors visible locally are stale-metadata artifacts from incremental builds with prior struct shapes; CI's clean build resolves them and tests/*.rs files do not construct any of the touched types. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OpenHuman
The age of super intelligence is here. OpenHuman is your Personal AI super intelligence. Private, Simple and extremely powerful.
Discord • Reddit • X/Twitter • Docs
"The Tet. What a brilliant machine" — Morgan Freeman as he reminisces about alien superintelligence in the movie Oblivion
Early Beta — Under active development. Expect rough edges.
To install or get started, either download from the website over at tinyhumans.ai/openhuman or run
# For MacOS/Linux
curl -fsSL https://raw.githubusercontent.com/tinyhumansai/openhuman/main/scripts/install.sh | bash
# For Windows
irm https://raw.githubusercontent.com/tinyhumansai/openhuman/main/scripts/install.ps1 | iex
What is OpenHuman?
OpenHuman is an open-source agentic assistant that is designed to integrate with you in your daily life. Here's what makes OpenHuman special:
-
Simple, UI-first — A clean desktop experience and short onboarding paths so you can go from install to a working agent in a few clicks, without a config-first setup. You don't need a terminal to run OpenHuman.
-
One subscription, many providers — You only need one account to get access to many agentic APIs (AI Models, Search, Webhooks/Tunnels and other 3rd party APIs etc..), simplifying the experience to get a powerful agent going.
-
Rich Skills — Plug into Gmail, Slack, Notion, and the rest of your stack via rich, feature-backed skills. Connections are typically one click through setup wizards instead of wiring APIs by hand. Workflow data is kept on device, encrypted locally, and treated as yours: encryption and sensitive context stay on your machine. Webhooks give instant feedback into the agent when external systems or skills emit events, so the loop stays tight without constant polling.
-
Local knowledge base — Built from your data and your activity. How you work across tools, sessions, and connected services—so the agent gets rich, workflow-aware context, not a one-off chat transcript. Everything is stored on your machine and compounding over time without becoming a cloud dossier. Channels, skills and ongoing conversations feed the same loop so day-to-day context does not reset every session.
-
Local AI model — The Rust core exposes local AI paths (and the desktop bundle can ship local/bundled runners where applicable) for the workloads above—vision snippets, speech helpers, summarization, tooling—so sensitive steps can stay off the cloud when you choose.
-
Deep desktop integrations — OpenHuman is a native desktop assistant, not a web-only chat: memory-aware keyboard autocomplete, voice (STT listening and TTS replies), screen intelligence that understands what is on screen and feeds your local context, plus windowing and OS-level permissions—so the agent meets you on the machine, not trapped in a browser tab.
Architecture: docs/ARCHITECTURE.md. Contributor orientation: CONTRIBUTING.md. Running from source: docs/install.md.
Highlights
- Neocortex — local-first knowledge base that learns from your data and activity, compounding context across tools and sessions.
- The Subconscious — background self-learning loops that turn everyday usage into workflow-aware intelligence.
- Screen Intelligence — the agent sees what's on your screen and feeds it into your local context.
- Inline Autocomplete — memory-aware keyboard autocomplete anywhere on your desktop.
- Voice (STT + TTS) — speak to OpenHuman and hear it reply, natively on the desktop.
- Skills & Integrations — one-click skills for Gmail, Slack, Notion and the rest of your stack, with local encryption and webhooks for instant feedback.
- Messaging Channels — inbound/outbound across the channels you already use, routed through your agent.
- Teams & Organizations — shared workspaces for collaborating with an agent across a team.
- Rewards & Achievements — gamified progression as your agent grows with you.
- Privacy & Security — workflow data stays on device, encrypted locally, and treated as yours.
OpenHuman vs other agents
High-level comparison (products evolve—verify against each vendor). OpenHuman is built to minimize vendor sprawl, keep workflow knowledge on-device, and ship deep desktop features—not only chat.
| Claude Code/Cowork | OpenClaw | Hermes Agent | OpenHuman | |
|---|---|---|---|---|
| Open-source | 🚫 Proprietary | ✅ MIT | ✅ MIT | ✅ GNU |
| Simple to start | ✅ Desktop + CLI | ⚠️ Terminal-first | ⚠️ Terminal-first | ✅ Clean UI, minutes |
| Cost | ⚠️ Sub + add-ons | ⚠️ BYO models | ⚠️ BYO models | ✅ Local-friendly |
| Memory & KB | ✅ Chat-scoped | ⚠️ Plugin-reliant | ✅ Self-learning | 🚀 Local KB + learning |
| API sprawl | 🚫 Extra keys | 🚫 BYOK | 🚫 Multi-vendor | ✅ One account |
| Extensibility | ✅ MCP | ✅ SKILL.md | ✅ SKILL.md | 🚀 Rich Skills |
| Desktop integration | ⚠️ Basic | ⚠️ Light | ⚠️ Light | ✅ STT/TTS/screen/more |
Contributors Hall of Fame
Show some love and end up in the hall of fame
