feat(backend): BACKEND_SLOT_PINNING — per-phase engine slot ownership

Each pipeline phase owns one llama-server slot (steward 0, orchestrator
1, synthesizer 2), carried as id_slot in extra_body through the same
mechanism tool_choice already uses, so the phase's stable prompt prefix
stays in that slot's KV cache and a turn re-prefills only its new
tokens. Off by default; a no-op on the Claude backend and ignored by
Ollama, so the flag is safe on any backend and the cutover itself stays
a pure env swap.

The merge helper preserves existing extra_body keys — mutation-checked
(dropping the merge fails exactly the test written for it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 22:25:53 +02:00
co-authored by Claude Fable 5
parent 9ff698b55d
commit 23217bdb26
6 changed files with 80 additions and 10 deletions
+29
View File
@@ -91,3 +91,32 @@ class TestGetModelInfo:
info = model_selector.get_model_info()
assert info["backend"] == "claude"
assert info["model"] == config.ANTHROPIC_MODEL
class TestWithSlotPinning:
def test_disabled_returns_settings_unchanged(self, local_first, monkeypatch):
monkeypatch.setattr(config, "BACKEND_SLOT_PINNING", False)
base = model_selector.get_tool_choice_settings()
assert model_selector.with_slot_pinning(base, slot=1) is base
assert model_selector.with_slot_pinning(None, slot=2) is None
def test_enabled_merges_slot_with_existing_extra_body(self, local_first, monkeypatch):
monkeypatch.setattr(config, "BACKEND_SLOT_PINNING", True)
settings = model_selector.with_slot_pinning(
model_selector.get_tool_choice_settings(), slot=1
)
extra_body = settings["extra_body"]
assert extra_body["id_slot"] == 1
# tool_choice from the base settings survives the merge
assert extra_body["tool_choice"] == "required"
def test_enabled_pins_bare_settings(self, local_first, monkeypatch):
monkeypatch.setattr(config, "BACKEND_SLOT_PINNING", True)
settings = model_selector.with_slot_pinning(None, slot=2)
assert settings["extra_body"] == {"id_slot": 2}
def test_claude_backend_never_pinned(self, local_first, monkeypatch):
monkeypatch.setattr(config, "BACKEND_SLOT_PINNING", True)
monkeypatch.setattr(config, "PREFER_CLOUD_BACKEND", True)
base = model_selector.get_tool_choice_settings()
assert model_selector.with_slot_pinning(base, slot=1) is base