Skip to content

Force gemma4 to reason - #95

Merged
MegalithOfficial merged 6 commits into
LettuceAI:mainfrom
Husky110:force-gemma4-to-reason
Sep 3, 2026
Merged

Force gemma4 to reason#95
MegalithOfficial merged 6 commits into
LettuceAI:mainfrom
Husky110:force-gemma4-to-reason

Conversation

@Husky110

@Husky110 Husky110 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Adds a per-model "Force Reasoning in Gemma4-series models" toggle in the Reasoning section of the model settings, only when llama.cpp is the active provider. When enabled and the model runs on the local llama.cpp engine, the assistant reply is prefilled with an opening thought channel so Gemma4-series models are forced to reason before answering.

Also, the toggle removes the necessity to create duplicate systemprompts to force Gemma4-series models to reason.

And the general fallback-URL is set to http://localhost/ to prevent people from heart-attacks when looking at the debug-window.

Adds a per-model "Force Reasoning in Gemma4-series models" toggle in the
Reasoning section of the model settings. When enabled and the model runs
on the local llama.cpp engine, the assistant reply is prefilled with an
opening thought channel so Gemma4-series models are forced to reason
before answering.

Frontend:
- New forceGemma4Reasoning field in the advanced model settings schema,
  editor controller, and form mapping.
- Toggle is only rendered for the llamacpp provider and is reset when the
  provider is switched to anything else, so it can never linger active on
  a remote provider.
- i18n keys added and translated across all 20 locales; parameter-support
  labels updated.

Backend:
- AdvancedModelSettings gains force_gemma4_reasoning.
- build_provider_extra_fields injects a forceGemma4Reasoning body flag,
  gated on provider_id == "llamacpp".
- The llama.cpp desktop path carries the flag through
  OpenAICompatPromptOptions and appends the GEMMA4_REASONING_PREFILL
  ("<|channel>thought") to the built prompt after the generation prompt.
resolve_base_url fell back to https://api.openai.com for any provider not
in the config list. The embedded llama.cpp engine is not in that list, so
its (never-used) request URL resolved to the OpenAI endpoint, which showed
up in the debug view and misleadingly implied traffic was sent to OpenAI.

Every real HTTP provider — OpenAI included — has its own entry with an
explicit default_base_url, so this fallback only ever fires for
unregistered providers. Default it to http://localhost instead, so the
debug view reflects that llama.cpp requests stay local.
…Gemma4 reasoning

When the forced-reasoning toggle is active on llama.cpp, the system prompt
now automatically starts with a "<|think|>\n" opener, so users no longer
have to paste it into the system prompt by hand.

The opener is prepended into the single leading system message rather than
added as a separate one, since Gemma chat templates reject conversations
with more than one system message. This complements the existing
"<|channel>thought" reply prefill driven by the same toggle.
…d-to-end

The forced-reasoning toggle did not actually work: the forceGemma4Reasoning
body flag was silently dropped, and even once delivered the reasoning block
leaked into the visible message.

- Allowlist the forceGemma4Reasoning extra-body key for llamacpp, so the
  flag survives strip_provider_incompatible_extra_fields and reaches the
  local engine (previously it was filtered out and never arrived).
- Give the reply prefill a trailing newline ("<|channel>thought\n") so the
  model starts at the content position instead of the opener/newline
  boundary where it sometimes closed the channel with an empty thought.
- Because the opener is prefilled into the prompt, the model output begins
  mid-thought and never emits the open tag. Start the thinking parser
  already inside the reasoning block (closing at "<channel|>") for both the
  streamed deltas and the final message assembly, so the reasoning goes to
  the reasoning field instead of leaking into the saved/visible content.
- Surface the final prompt (including the appended prefill) in the
  llama_runtime debug payload, and apply the prefill to the built prompt
  before it is logged/tokenized, to make the injected text inspectable.
llamaAdaptiveTarget and llamaAdaptiveDecay were emitted by
build_llama_extra_fields but never added to the llamacpp allowlist, so
strip_provider_incompatible_extra_fields dropped them from every request
and the adaptive-p sampler silently ran without its target/decay controls.

Add both keys to the allowlist, and populate them in the coverage test
fixture (count 42 -> 44) so the allowlist guard catches a missing entry
like this in the future.
@MegalithOfficial
MegalithOfficial merged commit e4f6a43 into LettuceAI:main Sep 3, 2026
5 checks passed
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.

2 participants