"""GenAI subsystem: protocol + fake client + invocation-result dataclasses. Real backends (Ollama, …) plug in behind :class:`GenAIClient`. The factory :func:`make_genai_client` picks between :class:`FakeGenAIClient` (for CI / hermetic tests via ``IX_TEST_MODE=fake``) and :class:`OllamaClient` (production). Tests that want a real Ollama client anyway can call the constructor directly. """ from __future__ import annotations from ix.config import AppConfig from ix.genai.client import GenAIClient, GenAIInvocationResult, GenAIUsage from ix.genai.fake import FakeGenAIClient from ix.genai.ollama_client import OllamaClient def make_genai_client(cfg: AppConfig) -> GenAIClient: """Return the :class:`GenAIClient` configured for the current run. When ``cfg.test_mode == "fake"`` the fake is returned; the pipeline callers are expected to override the injected client via DI if they want a non-default canned response. Otherwise a live :class:`OllamaClient` bound to ``cfg.ollama_url`` and the per-call timeout is returned. """ if cfg.test_mode == "fake": return FakeGenAIClient(parsed=None) return OllamaClient( base_url=cfg.ollama_url, per_call_timeout_s=float(cfg.genai_call_timeout_seconds), ) __all__ = [ "FakeGenAIClient", "GenAIClient", "GenAIInvocationResult", "GenAIUsage", "OllamaClient", "make_genai_client", ]