AI: backend Ollama + wybór modelu w komendzie przełączania #25
Reference in New Issue
Block a user
Delete Branch "ai-ollama-provider"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Co daje
Bot mówił przez OpenAI albo Anthropic. Dochodzi Ollama — modele hostowane u nas — a komenda przełączania pozwala wybrać który model, nie tylko który backend.
Jak wpięte
Ollama wystawia OpenAI-kompatybilne
/v1, więc klient to po prostuopenai.AsyncOpenAI(base_url=OLLAMA_URL + "/v1"). Dzięki temu reużywamy istniejący format wiadomości i całe mapowanie błędów (_map_openai_error) zamiast dublować drugą taksonomię. Klucza API nie ma — endpoint JEST konfiguracją, więc backend jest uśpiony i odmawia wyboru (z komunikatem podającym nazwę zmiennej), dopóki nie ustawiszCONJURER_OLLAMA_URL.Wybór modelu
$modele_ai [config]— pyta serwer (/v1/models), więc pokazuje to, co realnie masz wgrane, a nie listę zaszytą w kodzie.$gadaj_teraz ollama <model>— przełącza i przypina model (trwale). Model, którego Ollama nie ma, jest odrzucany od razu z prawdziwą listą — inaczej literówka wyszłaby dopiero jako nieudana odpowiedź.cheap_model(ścieżka MUSIC) zostaje nietknięty.Dwie rzeczy, które to odsłoniło
AI_CONFIGSscala wbudowane domyślne z blokiem z pliku ustawień. Każde przełączenie zapisuje blokconfigs, więc plik zapisany starszą wersją na stałe ukryłby nowo dodanego providera.CONJURER_AI_TIMEOUT_SECONDS— model na domowym GPU może potrzebować więcej.Regresja złapana przez adversarialny review (drugi commit)
Pierwsza wersja zapisywała cały blok
configsprzy każdym przełączeniu. To kasowało ręczne edycje operatora (jedyny sposób na zmianęcheap_model/temperature), wskrzeszało usunięte configi i unieważniałoCONJURER_OLLAMA_MODEL. Odtworzone na realnym kodzie, nie wywnioskowane. Poprawka jest węższa niż revert: zapisujemy tylko to pole, które ten proces faktycznie zmienił.Ścieżka zapisu na dysk nie miała żadnego pokrycia — i tak to weszło. Dołożone 4 testy jadące realny
_persist_active_ai_configna tymczasowym pliku; zweryfikowane mutacyjnie, że mają zęby (cofnięcie poprawki wywala 2 z nich). Plus utwardzone 2 słabe testy: jeden asertował na obiekcie zwracanym przezset_active_model(czyli na tym samym, zmutowanym dict — przechodził zawsze), drugi ustawiałOLLAMACLIENTnaNone, gdy i tak już byłNone.Do ustawienia u Ciebie
CONJURER_OLLAMA_URL— podaj mi adres Twojej Ollamy, to dorzucę go do manifestów deploya (bot testowy + deploy-bot). Sam nie zgaduję: pamięć opisuje Ollamę w LXC na pve2, a Ty piszesz o klastrze.Suite: 72 unit + 70 integration zielone.
🤖 Generated with Claude Code
Adversarial review of the previous commit found a real regression it introduced, reproduced against the actual code rather than inferred. Changing _persist_active_ai_config from setdefault("configs", ...) to a direct assignment made every backend switch write the whole in-memory AI_CONFIGS over the settings file. Because AI_CONFIGS is now the built-in defaults merged UNDER the file, that meant: * an operator's hand edits were destroyed - and hand editing is the only way to change cheap_model / temperature / max_tokens, since set_active_model writes latest_model and there is no command for the rest, * a config deliberately deleted from the file was re-seeded from the defaults and written back, permanently, * pinning a model for one provider silently reverted another provider's entry, * CONJURER_OLLAMA_MODEL stopped having any effect once the env-derived block had been persisted once. The original motivation was still valid (plain setdefault would drop a pinned model), so the fix is narrower rather than a revert: persist ONLY the field this process actually changed. _persist_active_ai_config takes model_for and writes back just that config's latest_model; everything else in the on-disk block is left exactly as found. The constants.py merge stays - it is what keeps a newly added provider visible after an upgrade - and is now in-memory only, so it cannot reach the file. Tests: the disk-write path had ZERO coverage, which is precisely how this got in. Added four tests that drive the real _persist_active_ai_config against a temp settings file: the pin lands while operator edits survive and a deleted config is not resurrected; a plain switch leaves the configs block byte-identical; a pin survives a re-read; a corrupt file does not raise. Verified they have teeth - reintroducing the regression fails two of them. Also hardened two weak tests the review caught: the pin test asserted on the object set_active_model returns, which IS the mutated dict (so it passed regardless), and the unconfigured-endpoint test monkeypatched OLLAMACLIENT to None when it was already None, passing vacuously. Suite: 72 unit + 70 integration green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>