Source code for src.dackar.RCA.orchestrators.llm_clients

"""
llm_clients — LLM client Protocol and concrete implementations.

Extracted from rca_reasoning_orchestrator.py.  The parent module re-exports
all three names for backward-compatible imports.
"""
from __future__ import annotations

import json
from typing import Any, Dict, Protocol

import requests

[docs] JsonDict = Dict[str, Any]
[docs] class LLMClient(Protocol):
[docs] def generate_json(self, model: str, prompt: str, temperature: float = 0.1) -> Dict[str, Any]: ...
[docs] class DummyLLMClient: """ Development-only LLM client used by build_dev_orchestrator(). Intentionally raises so the real synthesizer falls back to the deterministic template path. This lets the pipeline run end-to-end before Ollama or another real LLM backend is wired in. """
[docs] def generate_json(self, model: str, prompt: str, temperature: float = 0.1) -> JsonDict: raise RuntimeError( "DummyLLMClient intentionally forces fallback synthesis in local development." )
[docs] class OllamaLLMClient: def __init__(self, base_url: str = "http://localhost:11434"):
[docs] self.base_url = base_url.rstrip("/")
[docs] def generate_json(self, model: str, prompt: str, temperature: float = 0.1) -> Dict[str, Any]: payload = { "model": model, "prompt": prompt, "format": "json", "stream": False, "options": { "temperature": temperature, }, } resp = requests.post(f"{self.base_url}/api/generate", json=payload, timeout=120) resp.raise_for_status() data = resp.json() text = data.get("response", "").strip() if not text: raise RuntimeError("Ollama returned an empty response.") try: return json.loads(text) except json.JSONDecodeError as exc: raise RuntimeError(f"Ollama response was not valid JSON: {exc}") from exc