Beyond ICR: Incremental 'Suggesting' Read in Emacs

Beyond ICR: Incremental 'Suggesting' Read in Emacs

Beyond ICR: Incremental 'Suggesting' Read in Emacs

1. TLDR

This is the sixth post in my series on Emacs completion. The first argued that Incremental Completing Read (ICR) is a structural property of an interface, not an interface itself; the next four made it concrete with the VOMPECCC framework, my Spotify client (spot), a produce picker, and a VOMPECCC showcase. This one coins a term for a special case, Incremental Suggesting Read (ISR), where the candidate set produced by incrementally typed input is a suggestion, rather than a literal completion of that input. The ability to generate inferred matches in addition to literal matches vastly expands the scope of what a 'completion' system can do. Two conceptual sources supply the suggestions: 1) semantic retrieval and 2) generative synthesis.

This post is more speculative than useful, so carry that pinch of salt with you as you watch the video or read this post.

2. From completing to suggesting   icr isr definition

The initial post in this series broke down the 3 key words in ICR: read (type input), completing (match input against a candidate set), and incremental (recompute matches on every keystroke).

ISR is perfectly analgous, except the materialized candidate set is not a list of literal match candidates, but rather a list of inferred suggestions.

Put another way, in completing read, the candidates lexically correspond to your input. In suggesting read, a model infers candidates from your input.

In this post and video above, I discuss two sources of ISR:

  1. Semantic retrieval: the candidates are generated from concrete, existing data (notes, mail, code), and ISR ranks them by meaning, or semantic proximity to the input. A well established demo of this in Emacs is John Kitchin's "semantic completing read", which ranks Org files by embedding similarity to what your input 'means'.
  2. Generative synthesis: the candidate is written on demand (by an LLM) and is effectively non-existent prior to your input, which can appropriately be called a 'prompt' in these cases.

3. The same machinery, a different source   substrate thesis

Because Emacs built-ins (and of course VOMPECCC) are so strong, they can be used to support ISR use-cases. Everything we demonstrated in prior posts is relevant here, most of all the consult package.

The key enabler of ISR is the fact that completing-read's candidate collection can be a function: Emacs passes your input to a function, and that function returns the inferred suggestions. That's powerful in the abstract, and concretely it enables our semantic retreival and generative synthesis use cases.

Because Emacs clearly already supports this abstraction, everything downstream of the source (everything we've demonstrated in this series up until this point) is re-usable. In line with a common theme in Emacs, our precious, hard-earned muscle memory transfers perfectly from ICR to ISR.

consult is especially enabling of ISR because it is functionally optimized to supply candidates from a backend rather than a materialized list. We've already shown how we can hand consult a function (that hits an API) and consult supplies asynchronous fetching, keystroke debouncing, live preview, grouping, narrowing, and (optionally) Embark actions.

There are already public examples of ISR in action:

In the generative syntehsis case, an integration between 2 packages provides a beautful example. Armin's consult-omni ships with a consult interface to karthink's gptel in gptel source. This integration with gptel's suggesting backend is defined the same way as it would be with a completing backend, whether that's ripgrep or a search API. Another generative synthesis example would be completing for the possible LLM expansions of inline code or prose (think GitHub Copilot's Emacs extensions).

In the semantic retreival case, I implemented an example borrowing from John Kitchin's org-db-v3 for the embeddings.

The point of this section is that the existing ICR machinery (especially consult in this case) can be re-used for ISR. Below you can see how I reuse it. Pay special attention to consult--read and consult--dynamic-collection in my chiply-isr-semantic-read command:

(defun chiply-isr--collection (input)
  (mapcar (lambda (r)
            (cons (format "%-22s  %s"
                          (file-name-nondirectory (alist-get 'filename r))
                          (alist-get 'chunk_text r))
                  (alist-get 'filename r)))
          (chiply-isr--search input)))    ; embedding search over my sample corpus

;; consult drives that function as a live, per-keystroke source.
(defun chiply-isr-semantic-read ()
  (interactive)
  (find-file
   (consult--read
    (consult--dynamic-collection #'chiply-isr--collection
      :min-input 3 :debounce 0.3)
    :prompt "Suggesting read (by meaning): "
    :lookup #'consult--lookup-cdr
    :require-match t :sort nil)))

The suggesting --collection function is the only thing that differs from a completing character-matching source. The full chiply-isr module lives in my Emacs config, but I built it for this demo, so I don't recommend you use it.

4. What makes suggestion special   hci cognition

The primer praised ICR for its cued recall, an alleviation of the burden on recall, with a small tax on recognition. With ICR, you supply a fragment (almost an 'intuition' considering Orderless's flexible matching capabilities), then pay the incredibly cheap cognitive cost of recognizing your target from a winnowed candidate set.

ISR moves further from recall, and opens the door to speculation. In semantic retrieval you supply only a gesture at meaning, and in generative synthesis you supply a question. In this way, I think about the goal of ISR as exploration and discovery, and the goal of ICR as arriving at a destination.

In my opinion, ISR's real value props are 1) reaching candidates that literal matching can't (semantic retreival), and 2) providing detailed answers to open questions and possible expansions (generative synthesis).

5. Notes on the demo

The demos from the companion video, and where their code lives in my Emacs config:

  • Semantic retrieval (match candidates by meaning)
  • Generative synthesis (generated output from LLMs)