68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
llm.py — LLM interaction layer for The Chaos engine.
|
|
|
|
Provides the low-level call_llm function and environment variable setup
|
|
for provider-specific auth.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from .state import append_llm_log
|
|
|
|
|
|
def set_llm_env(model: str, api_key: str | None, api_base: str | None) -> None:
|
|
"""Set provider-specific env vars for litellm."""
|
|
prefix = model.split("/")[0].upper()
|
|
key = api_key or "sk-placeholder"
|
|
os.environ[f"{prefix}_API_KEY"] = key
|
|
if api_base:
|
|
os.environ[f"{prefix}_API_BASE"] = api_base
|
|
|
|
|
|
def call_llm(
|
|
messages: list[dict],
|
|
*,
|
|
model: str | None = None,
|
|
temperature: float | None = None,
|
|
timeout: int | None = None,
|
|
max_tokens: int | None = None,
|
|
label: str = "",
|
|
) -> str | None:
|
|
"""Make a single LLM call. Loads config automatically. Returns content text or None on error."""
|
|
from .config import load_config
|
|
cfg = load_config().get("llm", {})
|
|
model = model or cfg.get("model", "ollama/llama3.1")
|
|
temperature = temperature if temperature is not None else cfg.get("temperature", 0.8)
|
|
timeout = timeout if timeout is not None else cfg.get("timeout", 120)
|
|
max_tokens = max_tokens if max_tokens is not None else cfg.get("max_tokens", 4096)
|
|
api_key = cfg.get("api_key")
|
|
api_base = cfg.get("api_base")
|
|
set_llm_env(model, api_key, api_base)
|
|
try:
|
|
import litellm
|
|
except ImportError:
|
|
return None
|
|
try:
|
|
response = litellm.completion(
|
|
model=model,
|
|
messages=messages,
|
|
temperature=temperature,
|
|
stream=False,
|
|
timeout=timeout,
|
|
max_tokens=max_tokens,
|
|
)
|
|
content = getattr(response.choices[0].message, 'content', None) or ""
|
|
reasoning = getattr(response.choices[0].message, 'reasoning_content', None) or ""
|
|
if reasoning and reasoning not in content:
|
|
append_llm_log(f"\n--- {label} [reasoning] ---\n{reasoning}")
|
|
text = content or reasoning
|
|
append_llm_log(f"\n--- {label} ---\n{text}")
|
|
return text
|
|
except Exception as e:
|
|
err_msg = f"{type(e).__name__}: {e}"
|
|
append_llm_log(f"\n--- LLM ERROR ({label}) ---\n{err_msg}")
|
|
return None
|