Liking cljdoc? Tell your friends :D

vaelii.impl.llm.selection

The selection-scoped prompt: the unit of work is a set of handles, not the KB.

vaelii.impl.llm.prompt renders the whole vocabulary — every context, type and predicate — and vaelii.impl.llm.tools renders every read as a tool schema. Both are fixed costs that grow with the KB, and against the schema-only starter (no individuals, no facts) they already come to ~8,800 tokens before the user has said anything. A KB heading for 100M sentexes cannot pay that per request, and a model with no tools capability cannot spend half of it at all.

So this namespace prompts about what the reader selected:

  1. the selected sentexes as the editor's own [sentence context] lines,
  2. a vocabulary card computed only from the terms those lines mention — each term's comment, its argIsa constraints, its place in the genl hierarchy, and its metadata,
  3. the reader's instruction.

Every read is pinned by a term the selection actually contains (comment-of, an argIsa query on a fixed predicate, a genl closure lookup), so the prompt is O(selection) and flat in KB size. Ten sentexes cost the same in a KB of ten as in a KB of a hundred million.

The model rewrites lines; it does not write. Its answer is the edited line set, which vaelii.impl.llm.session/propose-edit diffs against the selection by content to produce the {:add … :remove …} batch — the same diff the browser's editor does on Save, so an unchanged line touches nothing.

Nothing here truncates. A selection too big for the context window is a clean refusal (budget-problem), because the alternative is Ollama silently dropping the front of the reader's own selection.

The selection-scoped prompt: **the unit of work is a set of handles, not the KB.**

`vaelii.impl.llm.prompt` renders the whole vocabulary — every context, type and
predicate — and `vaelii.impl.llm.tools` renders every read as a tool schema.  Both
are fixed costs that grow with the KB, and against the schema-only starter (no
individuals, no facts) they already come to ~8,800 tokens before the user has said
anything.  A KB heading for 100M sentexes cannot pay that per request, and a model
with no `tools` capability cannot spend half of it at all.

So this namespace prompts about **what the reader selected**:

1. the selected sentexes as the editor's own `[sentence context]` lines,
2. a vocabulary card computed *only* from the terms those lines mention — each
   term's `comment`, its `argIsa` constraints, its place in the genl hierarchy, and
   its metadata,
3. the reader's instruction.

Every read is pinned by a term the selection actually contains (`comment-of`, an
`argIsa` query on a fixed predicate, a genl closure lookup), so the prompt is
**O(selection)** and flat in KB size.  Ten sentexes cost the same in a KB of ten as
in a KB of a hundred million.

**The model rewrites lines; it does not write.**  Its answer is the edited line set,
which `vaelii.impl.llm.session/propose-edit` diffs against the selection by content
to produce the `{:add … :remove …}` batch — the same diff the browser's editor does
on Save, so an unchanged line touches nothing.

**Nothing here truncates.**  A selection too big for the context window is a clean
refusal (`budget-problem`), because the alternative is Ollama silently dropping the
front of the reader's own selection.
raw docstring

budgetclj

(budget system user n-lines num-ctx)

What a request of this shape costs against a window, as {:prompt :reserved :total :num-ctx :headroom} — all in estimated tokens.

What a request of this shape costs against a window, as
`{:prompt :reserved :total :num-ctx :headroom}` — all in estimated tokens.
raw docstring

budget-problemclj

(budget-problem {:keys [prompt reserved total num-ctx headroom]} n-lines)

The message explaining why this request does not fit num-ctx, or nil when it does.

A selection that does not fit is refused, never trimmed. Ollama silently drops the front of an over-long prompt, so a truncating request would answer about part of the reader's selection while appearing to answer about all of it — the one failure mode a reviewer cannot see.

The message explaining why this request does not fit `num-ctx`, or nil when it does.

**A selection that does not fit is refused, never trimmed.**  Ollama silently drops
the front of an over-long prompt, so a truncating request would answer about part of
the reader's selection while appearing to answer about all of it — the one failure
mode a reviewer cannot see.
raw docstring

chars-per-tokenclj

Characters per token, for sizing a prompt before sending it. Deliberately low — measured English-plus-s-expressions runs near 4, so 3.5 over-estimates, and an over-estimate refuses a selection that would have just fit rather than letting one that does not fit be silently truncated.

Characters per token, for sizing a prompt before sending it.  Deliberately low —
measured English-plus-s-expressions runs near 4, so 3.5 **over**-estimates, and an
over-estimate refuses a selection that would have just fit rather than letting one
that does not fit be silently truncated.
raw docstring

clipclj

(clip s n)

A KB string folded to one line and cut to n characters — a card is a reminder, not a manual. Public because every prompt section in this package clips the same way, and two copies of it would drift apart.

A KB string folded to one line and cut to `n` characters — a card is a reminder, not a
manual.  Public because every prompt section in this package clips the same way, and
two copies of it would drift apart.
raw docstring

edit-lineclj

(edit-line s)

The one editable EDN line for a sentex: [sentence context], plus {:strength :monotonic} when it is known-true, so a rewrite keeps it.

The one editable EDN line for a sentex: `[sentence context]`, plus
`{:strength :monotonic}` when it is known-true, so a rewrite keeps it.
raw docstring

estimate-tokensclj

(estimate-tokens s)

A conservative token count for a string. An estimate is what there is: Ollama exposes no tokenizer endpoint, and the exact count only comes back on the response as prompt_eval_count — which is the number to check an estimate against, and the reason propose-edit reports both.

A conservative token count for a string.  An estimate is what there is: Ollama
exposes no tokenizer endpoint, and the exact count only comes back on the response
as `prompt_eval_count` — which is the number to check an estimate against, and the
reason `propose-edit` reports both.
raw docstring

output-schemaclj

A JSON schema for Ollama's format parameter — an optimization, not the contract.

format is not portable: measured on this task, phi4:14b and qwen2.5-coder:32b honour it, while qwen3.6:27b and nemotron-3-nano:30b ignore it outright and answer in the line format anyway — one of them wrapping its JSON in a markdown fence even with the schema set. So the contract is the editor's own line format (which every model produces readily, and which makes the round trip through the editor the identity), and this schema is opt-in for a model it demonstrably helps. vaelii.impl.llm.session/parse-lines reads either shape.

When it is used: an object per line, never a bare string. A free string field lets the model choose a shape, and a 14B one quietly drops the enclosing brackets.

A JSON schema for Ollama's `format` parameter — **an optimization, not the
contract.**

`format` is not portable: measured on this task, `phi4:14b` and `qwen2.5-coder:32b`
honour it, while `qwen3.6:27b` and `nemotron-3-nano:30b` ignore it outright and answer
in the line format anyway — one of them wrapping its JSON in a markdown fence even
with the schema set.  So the contract is the **editor's own line format** (which every
model produces readily, and which makes the round trip through the editor the
identity), and this schema is opt-in for a model it demonstrably helps.
`vaelii.impl.llm.session/parse-lines` reads either shape.

When it is used: an **object per line**, never a bare string.  A free string field
lets the model choose a shape, and a 14B one quietly drops the enclosing brackets.
raw docstring

reserved-output-tokensclj

(reserved-output-tokens n-lines)

The output room a selection needs: one line back per line in, with slack for the lines it invents and for prose it was told not to write. Reserved out of the window, because a prompt that fits with no room to answer is a prompt that does not fit.

The output room a selection needs: one line back per line in, with slack for the
lines it invents and for prose it was told not to write.  Reserved out of the window,
because a prompt that fits with no room to answer is a prompt that does not fit.
raw docstring

selectedclj

(selected kb handles)

The selection as [{:handle :sentex :key [sentence context] :strength :line "…"} …], in the caller's handle order, silently dropping a handle with no stored sentex (the page it was selected on can be older than the KB). :key is the content the diff is taken on — the same pair the editor diffs by.

The selection as `[{:handle :sentex :key [sentence context] :strength :line "…"} …]`,
in the caller's handle order, silently dropping a handle with no stored sentex (the
page it was selected on can be older than the KB).  `:key` is the content the diff
is taken on — the same pair the editor diffs by.
raw docstring

system-promptclj

The instruction half — static, because everything KB-specific rides in the user turn where the selection is. It is deliberately short: the window belongs to the reader's content, not to a manual, and the deterministic critic (vaelii.impl.llm.session/check-batch) catches what the prose does not.

The output contract is the editor's line format, so what the model writes is exactly what the textarea already holds and the round trip is the identity.

The instruction half — static, because everything KB-specific rides in the user turn
where the selection is.  It is deliberately short: the window belongs to the reader's
content, not to a manual, and the deterministic critic
(`vaelii.impl.llm.session/check-batch`) catches what the prose does not.

The output contract is the **editor's line format**, so what the model writes is
exactly what the textarea already holds and the round trip is the identity.
raw docstring

terms-inclj

(terms-in rows)

Every symbol the selection mentions, plus each line's context — the terms the card is computed over. Variables, numbers and strings carry no vocabulary, so they are dropped; nesting depth does not matter, since a term buried in a rule's antecedent is as much part of what the reader selected as its consequent's predicate.

Every symbol the selection mentions, plus each line's context — the terms the card
is computed over.  Variables, numbers and strings carry no vocabulary, so they are
dropped; nesting depth does not matter, since a term buried in a rule's antecedent
is as much part of what the reader selected as its consequent's predicate.
raw docstring

tickclj

(tick x)

A term in backticks, so a model reads it as a name rather than as prose.

A term in backticks, so a model reads it as a name rather than as prose.
raw docstring

ticksclj

(ticks xs)

Backticked terms, comma-joined.

Backticked terms, comma-joined.
raw docstring

user-turnclj

(user-turn kb rows instruction)
(user-turn kb rows instruction opts)

The volatile half: the selected lines, the vocabulary card computed from them, and the reader's instruction — in that order, instruction last so it is the newest thing in the window.

The volatile half: the selected lines, the vocabulary card computed from them, and
the reader's instruction — in that order, instruction last so it is the newest thing
in the window.
raw docstring

vocabulary-cardclj

(vocabulary-card kb rows)
(vocabulary-card kb rows {:keys [max-terms] :or {max-terms 60} :as opts})

The vocabulary the selection actually uses, as markdown.

Terms are grouped by naming role and each is described from the KB: a predicate or type by its argIsa constraints, supertypes, sub-predicates, disjointness, metadata and documentation; an individual by its types; a context by what it sees. Types share the predicate section because they are unary predicates and term-role reads a one-word dog as either. opts: :max-terms (60), :max-relatives (12), :max-doc-chars (160).

Nothing here enumerates the KB — every read is pinned by a term the selection contains — so the card's size tracks the selection, not the knowledge base.

The vocabulary the selection actually uses, as markdown.

Terms are grouped by naming role and each is described from the KB: a
predicate or type by its `argIsa` constraints, supertypes, **sub-predicates**,
disjointness, metadata and documentation; an individual by its types; a context by
what it sees.  Types share the predicate section because they *are* unary predicates
and `term-role` reads a one-word `dog` as either.  `opts`: `:max-terms` (60),
`:max-relatives` (12), `:max-doc-chars` (160).

Nothing here enumerates the KB — every read is pinned by a term the selection
contains — so the card's size tracks the selection, not the knowledge base.
raw docstring

wrapped-sentenceclj

(wrapped-sentence s)

A sentex's editable sentence: the readable sentence (the author's variable names), and for a rule its direction / defeasibility spelled back as set/*Rule wrappers so a re-assert preserves them. A rule's exceptWhen / unknown guard lives in a separate meta-sentex and is not carried.

A sentex's editable sentence: the readable sentence (the author's variable names),
and for a rule its direction / defeasibility spelled back as `set/*Rule` wrappers so
a re-assert preserves them.  A rule's `exceptWhen` / `unknown` guard lives in a
separate meta-sentex and is not carried.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close