Skip to content

Samplers: Remove ability to specify "full-context windows" from history-based samplers - #26524

Merged
ggerganov merged 2 commits into
masterfrom
osimons/penalty_sampler_folllow_up_no2
Aug 4, 2026
Merged

ggerganov merged 2 commits into
masterfrom
osimons/penalty_sampler_folllow_up_no2

Conversation

@ORippler

@ORippler ORippler commented Aug 3, 2026 •

Copy link
Copy Markdown
Collaborator

Overview

  1. Because of backend-sampling we initialize samplers before the complete llama_context is there. Therefore, we cannot infer the resolved context length yet at the time we construct the samplers.
  2. Review of Add backend sampler for penalties sampler #25262 (comment) therefore suggested removing the ability to specify full-context for history-penalizers, and this PR implements it

Additional information

  • we reject penalty_last_n < 0 in all consumers, but clamp them to 0 when directly constructing samplers via libllama
  • used 64 as a shared default instead of the suggested 1024. Can adjust as needed as this PR is breaking anyways.
  • I did not evaluate whether this needs to be a stacked PR, just wanted to try out the feature

Requirements

@ORippler
ORippler requested review from a team, ggerganov and ngxson as code owners August 3, 2026 15:58
@github-actions github-actions Bot added documentation Improvements or additions to documentation testing Everything test related server mtmd Related to multimodal functionality (video/image/audio) server/ui labels Aug 3, 2026
@ggerganov
ggerganov force-pushed the osimons/penalty_sampler_folllow_up_no2 branch from 31f798a to 60abc26 Compare August 3, 2026 16:10
Base automatically changed from osimons/penalty_sampler_folllow_up to master August 4, 2026 06:02
@ggerganov
ggerganov requested a review from CISC as a code owner August 4, 2026 06:02
Because of backend-sampling we initialize samplers before the complete
llama_context is there. Therefore, we cannot infer the resolved context
length yet at the time we construct the samplers.
@ggerganov
ggerganov force-pushed the osimons/penalty_sampler_folllow_up_no2 branch from 60abc26 to eb75c42 Compare August 4, 2026 06:02
@ggerganov ggerganov added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Aug 4, 2026
@ggerganov
ggerganov merged commit a6aa6f5 into master Aug 4, 2026
25 of 32 checks passed
satindergrewal pushed a commit to satindergrewal/llama.cpp that referenced this pull request Aug 12, 2026
…gml-org#26524)

* Resolve -1 to 1024 instead of ctx-len for samplers

Because of backend-sampling we initialize samplers before the complete
llama_context is there. Therefore, we cannot infer the resolved context
length yet at the time we construct the samplers.

* Shared default of 64 for history-based samplers, remove context_size
brittlewis12 pushed a commit to brittlewis12/llama.cpp that referenced this pull request Aug 17, 2026
…gml-org#26524)

* Resolve -1 to 1024 instead of ctx-len for samplers

Because of backend-sampling we initialize samplers before the complete
llama_context is there. Therefore, we cannot infer the resolved context
length yet at the time we construct the samplers.

* Shared default of 64 for history-based samplers, remove context_size
thecodacus pushed a commit to thecodacus/llama.cpp that referenced this pull request Sep 7, 2026
…gml-org#26524)

* Resolve -1 to 1024 instead of ctx-len for samplers

Because of backend-sampling we initialize samplers before the complete
llama_context is there. Therefore, we cannot infer the resolved context
length yet at the time we construct the samplers.

* Shared default of 64 for history-based samplers, remove context_size
zbrad pushed a commit to zbrad/llama.cpp that referenced this pull request Sep 10, 2026
…gml-org#26524)

* Resolve -1 to 1024 instead of ctx-len for samplers

Because of backend-sampling we initialize samplers before the complete
llama_context is there. Therefore, we cannot infer the resolved context
length yet at the time we construct the samplers.

* Shared default of 64 for history-based samplers, remove context_size
@wwoodsTM

Copy link
Copy Markdown
Contributor

Hi @ORippler, late to the party here, but just wanted to raise a concern around DRY sampling (I authored the original PR that ported DRY to the project): a default as small as 64 means DRY can no longer see repetitions from more than a few sentences back, which is most of what it was built to catch in prose. While users can of course supply a higher dry-penalty-last-n, I wonder if a larger default for DRY, such as @ggerganov's earlier suggested value of 1024, might be considered?

@ORippler

Copy link
Copy Markdown
Collaborator Author

I wonder if a larger default for DRY, such as @ggerganov's earlier #25262 (comment), might be considered?

What are the key differences between DRY and repeat-penalty samplers that would warrant a higher default for the former? I thought they would be different flavors of the same and different thresholds would thus overcomplicate things unnecessarily.

@wwoodsTM

Copy link
Copy Markdown
Contributor

I wonder if a larger default for DRY, such as @ggerganov's earlier #25262 (comment), might be considered?

What are the key differences between DRY and repeat-penalty samplers that would warrant a higher default for the former? I thought they would be different flavors of the same and different thresholds would thus overcomplicate things unnecessarily.

Rep pen is per-token while DRY is sequence-based. Both samplers always had different defaults with rep pen at 64 since 2023 I believe and DRY at full context (-1) since its original PR in Oct. 2024. That split to my knowledge has worked well for the two years it was in effect and it relates to how the two behave very differently with a bigger context window.

For standard rep pen with its per-token handling things can get very hairy quickly with large contexts as it is very sensitive to any token that appears in the entire window like a name appearing multiple times and such, while for DRY it handles multi-token patterns and new tokens only get penalized if they extend a pattern that was seen before past a configured limit (dry_allowed_length), exponentially penalizing each extra token the more the model tries to extend the multi-token pattern.

Due to these differences, the two samplers sharing a default probably would hurt one or the other.

i386 pushed a commit to Mesh-LLM/mesh-llm that referenced this pull request Oct 3, 2026
## Title

fix(sampling): make repetition penalties take effect

## Original problem

`repeat_penalty`, `frequency_penalty` and `presence_penalty` did nothing
unless the request (or config) also set a positive `repeat_last_n`. The
same was true of DRY when `dry.penalty_last_n` was set to `-1`.

mesh defaulted `repeat_last_n` to `-1` and documented it as "use the
whole
context". llama.cpp dropped whole-context penalty windows upstream
(ggml-org/llama.cpp#26524) because backend sampling builds samplers
before
the context exists. Since then, a negative window passed to its
penalties
or DRY sampler is clamped to `0`, which disables the sampler. Our pin
includes that change, so every request that left the window at its
default
silently lost its penalties.

## Diagnostics

- At our pinned llama.cpp, `llama_sampler_init_penalties` and
`llama_sampler_init_dry` both do `std::max(window, 0)`, and a `0` window
  disables the sampler.
- skippy-server defaulted `repeat_last_n` to `-1`, and the native Skippy
  sampler passed it straight through.
- Current llama.cpp master still clamps the same way, so updating the
pin
  would not fix this. llama-server now defaults both windows to 64 and
  rejects negative values.

## Fix

The fix follows llama.cpp in Rust instead of patching it:

- Penalty and DRY windows default to 64 tokens, llama.cpp's default.
- `-1` is still accepted, as a legacy alias for that default, so
existing
configs and clients keep working. Values below `-1` are still rejected,
  and `0` still disables the penalties.
- The alias is applied when skippy-server parses a request, and again
just
  before the native call. The second catches older peers that send `-1`
  over the stage transport.
- A config that sets `repeat_last_n = -1` or `dry.penalty_last_n = -1`
  loads as before, with a warning:

  ```text
  defaults.request_defaults.repeat_last_n = -1 no longer means the whole
context; it uses the default window of 64 tokens. Set an explicit token
  count instead
  ```

- The config docs no longer promise whole-context windows.

**Behaviour change:** requests that set no penalty are unaffected.
Requests
that set a repeat, frequency or presence penalty without a positive
`repeat_last_n` now get it applied over the last 64 tokens, where before
they got nothing. Set `repeat_last_n = 0` to keep penalties off.

**Compatibility:** no wire, ABI or config schema changes. In
mixed-version
meshes, an older peer that sends `-1` to a new final stage gets the
64-token default, and a new peer that sends `64` to an older final stage
gets penalties over 64 tokens.

## Validation

- [x] I ran the relevant local checks, or explained why they do not
apply.
  - `cargo fmt --all --check`
  - `just no-console-print`
  - `cargo clippy --all-targets -- -D warnings` for `skippy-protocol`,
    `skippy-runtime`, `mesh-llm-config`, `skippy-server` and `mesh-llm`
- `cargo test --lib` passes for `skippy-protocol` (74), `skippy-runtime`
    (249), `mesh-llm-config` (224), `skippy-server` (872) and
    `mesh-llm-host-runtime` (4114). New tests:
    - `penalty_windows_resolve_legacy_whole_context_to_the_default`
      (request parsing)
    - `sampling_raw_resolves_penalty_windows_for_llama_cpp` (the native
      sampling config)
    - `whole_context_windows_warn_at_each_configured_path` and
      `explicit_windows_do_not_warn` (config warnings)
  - Not run: an end-to-end inference check that compares output with and
    without a penalty.
- [x] UI changes include screenshots or video, or explain why visual
aids are not needed.
  No UI changes.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Configuration**
* Repetition and DRY penalty windows now default to the most recent 64
tokens. Set a window to `0` to disable it; explicit nonnegative values
remain unchanged.
* Existing configurations using `-1` continue to work and use the
64-token default, with a compatibility warning. Values below `-1` are
rejected.
* **Documentation**
* Updated configuration guides to describe the 64-token defaults, the
effect of `0`, and the handling of legacy `-1` values.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. mtmd Related to multimodal functionality (video/image/audio) server/ui server testing Everything test related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants