Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ def _parse_viewer_allowed_origins() -> Any:
from automem.search.runtime_keywords import load_keyword_runtime
from automem.search.runtime_recall_helpers import (
_graph_keyword_search,
_metadata_keyword_search,
_result_passes_filters,
_vector_filter_only_tag_search,
_vector_search,
Expand Down
25 changes: 25 additions & 0 deletions automem/api/recall.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
FILTERABLE_RELATIONS,
RECALL_ADAPTIVE_FLOOR,
RECALL_EXPANSION_LIMIT,
RECALL_METADATA_SEARCH_ENABLED,
RECALL_MIN_SCORE,
RECALL_RELATION_LIMIT,
canonicalize_relation_type,
Expand Down Expand Up @@ -1417,6 +1418,7 @@ def handle_recall(
expansion_limit_default: Optional[int] = None,
on_access: Optional[Callable[[List[str]], None]] = None,
jit_enrich_fn: Optional[Callable[[str, Dict[str, Any]], Optional[Dict[str, Any]]]] = None,
metadata_keyword_search: Optional[Callable[..., List[Dict[str, Any]]]] = None,
):
query_start = time.perf_counter()
query_text = (request.args.get("query") or "").strip()
Expand Down Expand Up @@ -1666,6 +1668,27 @@ def _run_single_query(
)
local_results.extend(graph_matches[:remaining_slots])

if (
graph is not None
and metadata_keyword_search is not None
and query_str
and RECALL_METADATA_SEARCH_ENABLED
):
metadata_slots = max(1, min(per_query_limit, 10))
metadata_matches = metadata_keyword_search(
graph,
query_str,
metadata_slots,
local_seen,
start_time=start_time,
end_time=end_time,
tag_filters=tag_filters,
tag_mode=tag_mode,
tag_match=tag_match,
exclude_tags=exclude_tags,
)
local_results.extend(metadata_matches)

tags_only_request = (
not query_str
and not (embedding_param and embedding_param.strip())
Expand Down Expand Up @@ -2139,6 +2162,7 @@ def create_recall_blueprint(
summarize_relation_node: Callable[[Dict[str, Any]], Dict[str, Any]] | None = None,
on_access: Optional[Callable[[List[str]], None]] = None,
jit_enrich_fn: Optional[Callable[[str, Dict[str, Any]], Optional[Dict[str, Any]]]] = None,
metadata_keyword_search: Optional[Callable[..., List[Dict[str, Any]]]] = None,
) -> Blueprint:
bp = Blueprint("recall", __name__)

Expand Down Expand Up @@ -2170,6 +2194,7 @@ def recall_memories() -> Any:
expansion_limit_default=RECALL_EXPANSION_LIMIT,
on_access=on_access,
jit_enrich_fn=jit_enrich_fn,
metadata_keyword_search=metadata_keyword_search,
)

@bp.route("/startup-recall", methods=["GET"])
Expand Down
2 changes: 2 additions & 0 deletions automem/api/runtime_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def register_blueprints(
consolidation_tick_seconds: int,
consolidation_history_limit: int,
require_api_token_fn: Callable[[], None],
metadata_keyword_search_fn: Optional[Callable[..., list[dict[str, Any]]]] = None,
) -> None:
health_bp = create_health_blueprint(
get_memory_graph_fn,
Expand Down Expand Up @@ -106,6 +107,7 @@ def register_blueprints(
summarize_relation_node_fn,
update_last_accessed_fn,
jit_enrich_fn=jit_enrich_fn,
metadata_keyword_search=metadata_keyword_search_fn,
)

memory_bp = create_memory_blueprint_full(
Expand Down
2 changes: 2 additions & 0 deletions automem/api/runtime_recall_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def recall_memories(
emit_event_fn: Any,
utc_now_fn: Any,
abort_fn: Any, # noqa: ARG001 - kept for DI compatibility
metadata_keyword_search_fn: Any = None,
) -> Any:
query_start = perf_counter_fn()
query_text = (request_obj.args.get("query") or "").strip()
Expand Down Expand Up @@ -66,6 +67,7 @@ def recall_memories(
default_expand_relations=default_expand_relations,
relation_limit=recall_relation_limit,
expansion_limit_default=recall_expansion_limit,
metadata_keyword_search=metadata_keyword_search_fn,
)

elapsed_ms = int((perf_counter_fn() - query_start) * 1000)
Expand Down
6 changes: 6 additions & 0 deletions automem/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@
RECALL_EXPANSION_LIMIT = int(os.getenv("RECALL_EXPANSION_LIMIT", "25"))
RECALL_MIN_SCORE = float(os.getenv("RECALL_MIN_SCORE", "0.0"))
RECALL_ADAPTIVE_FLOOR = os.getenv("RECALL_ADAPTIVE_FLOOR", "true").lower() in ("true", "1", "yes")
RECALL_METADATA_SEARCH_ENABLED = os.getenv("RECALL_METADATA_SEARCH_ENABLED", "true").lower() not in {
"0",
"false",
"no",
}

# Memory content size limits (governs auto-summarization on store)
# Soft limit: Content above this triggers auto-summarization
Expand Down Expand Up @@ -447,6 +452,7 @@ def expand_relation_query_types(relation_types: Iterable[str]) -> list[str]:
# Search weighting parameters (can be overridden via environment variables)
SEARCH_WEIGHT_VECTOR = float(os.getenv("SEARCH_WEIGHT_VECTOR", "0.35"))
SEARCH_WEIGHT_KEYWORD = float(os.getenv("SEARCH_WEIGHT_KEYWORD", "0.35"))
SEARCH_WEIGHT_METADATA = float(os.getenv("SEARCH_WEIGHT_METADATA", "0.35"))
SEARCH_WEIGHT_TAG = float(os.getenv("SEARCH_WEIGHT_TAG", "0.2"))
Comment thread
jack-arturo marked this conversation as resolved.
SEARCH_WEIGHT_IMPORTANCE = float(os.getenv("SEARCH_WEIGHT_IMPORTANCE", "0.1"))
SEARCH_WEIGHT_CONFIDENCE = float(os.getenv("SEARCH_WEIGHT_CONFIDENCE", "0.05"))
Expand Down
1 change: 1 addition & 0 deletions automem/runtime_wiring.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def wire_recall_and_blueprints(
consolidation_tick_seconds=module.CONSOLIDATION_TICK_SECONDS,
consolidation_history_limit=module.CONSOLIDATION_HISTORY_LIMIT,
require_api_token_fn=module.require_api_token,
metadata_keyword_search_fn=module._metadata_keyword_search,
)


Expand Down
Loading
Loading