Skip to content

fix(context): honour an explicit context_size of 512 - #29

Merged
andinux merged 1 commit into
mainfrom
fix/context-size-512-sentinel
Aug 24, 2026
Merged

fix(context): honour an explicit context_size of 512#29
andinux merged 1 commit into
mainfrom
fix/context-size-512-sentinel

Conversation

@andinux

@andinux andinux commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Fixes the "context_size=512 is silently ignored" part of #28.

The bug

llm_context_create_with_options() decided whether the caller had asked for a context size by comparing the parsed value against llama's default:

struct llama_context_params defaults = llama_context_default_params();
if (ai->model && ctx_params.n_ctx == defaults.n_ctx) {
    ctx_params.n_ctx = 0;   // 0 = use the model's training window
}

That default is 512 (llama-context.cpp:2772) — a value a caller can perfectly well pass. So an explicit context_size=512 was indistinguishable from unset:

requested actual llm_context_size()
64 256
512 32768 — asked for 512, got 64× that
513 768
1000 1024

n_ctx=512 hit it too, since the check looked at the resolved value rather than at which key was written.

The fix

The intent was right; only the detection was wrong. llama.cpp already defines n_ctx = 0 as "use the training window", so start from that sentinel rather than inferring it after the fact:

struct llama_context_params ctx_params = llama_context_default_params();

// n_ctx = 0 tells llama.cpp to use the model's training window. Start from it so
// that "the caller did not ask for a context size" is an explicit sentinel rather
// than something inferred after the fact from the value [...]
ctx_params.n_ctx = 0;

and delete the comparison block. The caller's value now always survives, and 0 keeps its documented meaning. Net +1/−4 lines — no new struct, no signature changes, and no churn through the four llm_context_options_callback call sites (two of which pass xdata = NULL).

Also stops context_size=0 driving n_batch to 0, which llama will not accept.

Verified against the built extension:

option before after
context_size=256 256 256
context_size=512 32768 512
context_size=1024 1024 1024
n_ctx=512 32768 512
context_size=0 32768 32768
(omitted) 32768 32768

Behaviour change

Anyone passing context_size=512 or n_ctx=512 was getting the model's whole window and now gets 512. Nothing errors — the context simply becomes what was asked for, so a conversation that used to fit may now reach the limit.

That is the intended outcome: silently ignoring the configuration is the bug. It does make the other half of #28 easier to hit, where a full context returns an error and leaves the chat unusable for every subsequent turn. That issue stays open.

Patch version bump, 1.0.51.0.6.

Docs

API.md claimed llm_context_create_chat() and llm_context_create_textgen() were "equivalent to SELECT llm_context_create('context_size=4096')". Their presets are empty strings, so both inherit the model's training window. Corrected, and 0 is now documented on context_size and n_ctx.

Testing

test_context_size_is_honoured covers 256/512/1024 exactly — llama pads n_ctx up to a multiple of 256, so only exact multiples compare equal — plus both spellings, and that omitting the key or passing 0 still auto-sizes. It asserts the model trains above 1024 first, so it can actually tell an honoured size from an auto-sized one.

Verified to fail against a pre-fix build:

[context_size_is_honoured] context_size=512 produced n_ctx=32768
1 C test(s) failed. First failure: context_size_is_honoured

make test: 44/44 pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_012KRojTrn4Q4SaZQpqcwpAt

llm_context_create*() decided whether the caller had asked for a context size
by comparing the parsed value against llama_context_default_params().n_ctx:

    struct llama_context_params defaults = llama_context_default_params();
    if (ai->model && ctx_params.n_ctx == defaults.n_ctx) {
        ctx_params.n_ctx = 0;   // 0 = use the model's training window
    }

That default is 512 (llama-context.cpp:2772), a value a caller can perfectly
well pass, so an explicit context_size=512 was indistinguishable from unset and
was silently replaced by the model's full training window:

    context_size=64   -> n_ctx=256
    context_size=512  -> n_ctx=32768     <-- asked for 512, got 64x that
    context_size=513  -> n_ctx=768

n_ctx=512 hit it too, since the check looked at the resolved value rather than
at which key was written.

The intent was right, only the detection was wrong. llama.cpp already defines
n_ctx = 0 as "use the training window", so start from that sentinel instead of
inferring it after the fact: the caller's value now always survives, and 0 keeps
its documented meaning. Also stops context_size=0 driving n_batch to 0, which
llama will not accept.

Behaviour change, and a quiet one: anyone passing context_size=512 or n_ctx=512
was getting the model's whole window and now gets 512. Nothing errors - the
context simply becomes what was asked for, so a conversation that used to fit
may now reach the limit. That is the point: silently ignoring the configuration
is the bug. It does make #28 easier to hit, where a full context errors and
leaves the chat unusable.

API.md said llm_context_create_chat() and llm_context_create_textgen() were
equivalent to context_size=4096. Their presets are empty, so both inherit the
model's training window; documented as such, along with 0 on context_size/n_ctx.

test_context_size_is_honoured covers 256/512/1024 exactly (llama pads n_ctx to a
multiple of 256), both spellings, and that omitting the key - or passing 0 -
still auto-sizes. Verified to fail against the pre-fix build with
"context_size=512 produced n_ctx=32768".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KRojTrn4Q4SaZQpqcwpAt
@andinux
andinux merged commit a5d04a2 into main Aug 24, 2026
21 checks passed
andinux added a commit that referenced this pull request Aug 25, 2026
…on" typo

The remaining API.md errors recorded in notes/DEMO-FINDINGS.md, each re-verified
against the current build rather than taken on trust - that note was written
against 0.7.58.

embedding_type was documented as accepting BFLOAT16. It does not:
embedding_name_to_type() spells it FLOATB16, and anything unrecognised returns 0,
which surfaces as the "must be specified" error rather than as a bad-value one.
So a caller following the documentation got told they had omitted an option they
had in fact passed:

    embedding_type=BFLOAT16  ->  Embedding type (embedding_type) must be specified
    embedding_type=FLOATB16  ->  768 bytes

The entry now carries the right spelling, calls out that it is not BFLOAT16, and
quotes the error so the misleading message is at least searchable. All five
documented names verified against a 384-dimension model: 1536, 768, 768, 384, 384
bytes - exactly 4, 2, 2, 1 and 1 bytes per element.

json_output=1 was documented as returning "a JSON object". It returns a JSON
array: json_type() reports 'array' and the text begins '[-0.0355376,...'. Also
notes that the plain BLOB is what belongs in a sqlite-vector column, since
wrapping it is the mistake the JSON form invites.

The error message itself said "funtion". Fixed - nothing asserts on the string,
and the docs now quote it, so the two agreeing matters.

Two other items from that note are already handled: llm_context_create_chat()'s
phantom context_size=4096 preset went with #29, and llm_chat_restore()'s return
type earlier in this PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KRojTrn4Q4SaZQpqcwpAt
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.

1 participant