Skip to content

Sort completion candidates by frecency from history - #2158

Open
rolandwalker wants to merge 1 commit into
mainfrom
RW/calculate-history-frecency
Open

Sort completion candidates by frecency from history#2158
rolandwalker wants to merge 1 commit into
mainfrom
RW/calculate-history-frecency

Conversation

@rolandwalker

Copy link
Copy Markdown
Contributor

Description

  • calculate frecency for tokens in recent history, simply tokenizing and ignoring literals
  • recalculate frecency in a background thread every N queries at the REPL
  • sort completion candidates by frecency

A good followup could be making the sort-tuple returned by completion_sort_key() configurable.

Fixes #351.

Checklist

  • I added this contribution to the changelog.md file.
  • I added my name to the AUTHORS file (or it's already there).
  • To lint and format the code, I ran
    uv run ruff check && uv run ruff format && uv run mypy --install-types .

 * calculate frecency for tokens in recent history, simply tokenizing
   and ignoring literals
 * recalculate frecency in a background thread every N queries at the
   REPL
 * sort completion candidates by frecency

A good followup could be making the sort-tuple returned by
completion_sort_key() configurable.
@rolandwalker rolandwalker self-assigned this Aug 22, 2026
Comment thread mycli/main_modes/repl.py
return FileHistoryWithTimestamp(history_file)
configured_history_entries = mycli.config['main'].get('frecency_history_entries', FRECENCY_HISTORY_ENTRIES)
frecency_history_entries = int(configured_history_entries) if str(configured_history_entries).strip() else 0
frecency_refresh_interval = int(mycli.config['main'].get('frecency_refresh_interval', FRECENCY_REFRESH_INTERVAL))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have similar if/else logic as frecency_history_entries above?

return dict(frecency)


def frecency_score(text: str, frecency: Mapping[str, float]) -> float:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential for caching/memoization if you want to reduce load on larger schemas:

(mycli) arthlo@CAMELOT-2025:~/git/official-mycli$ git diff
diff --git a/mycli/packages/ptoolkit/history.py b/mycli/packages/ptoolkit/history.py
index ba14d38..78b2ba0 100644
--- a/mycli/packages/ptoolkit/history.py
+++ b/mycli/packages/ptoolkit/history.py
@@ -1,5 +1,6 @@
 from collections import defaultdict
 from collections.abc import Iterable, Mapping
+from functools import lru_cache
 from itertools import islice
 import logging
 import os
@@ -56,12 +57,18 @@ def _calculate_frecency(
     return dict(frecency)


-def frecency_score(text: str, frecency: Mapping[str, float]) -> float:
+@lru_cache(maxsize=8192)
+def _frecency_tokens(text: str) -> tuple[str, ...]:
+    """Tokenize a completion candidate. Cached: candidates repeat on every keystroke."""
     try:
         tokens = tokenize(text, dialect='mysql')
     except TokenError:
-        return 0.0
-    normalized_tokens = [normalized for token in tokens if (normalized := _normalize_frecency_token(token))]
+        return ()
+    return tuple(normalized for token in tokens if (normalized := _normalize_frecency_token(token)))
+
+
+def frecency_score(text: str, frecency: Mapping[str, float]) -> float:
+    normalized_tokens = _frecency_tokens(text)
     if not normalized_tokens:
         return 0.0
     return sum(frecency.get(token, 0.0) for token in normalized_tokens) / len(normalized_tokens)

@scottnemes scottnemes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added two comments for potential improvements if desired

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.

Feature Request: Sort tab completion by frequency

2 participants