llm_router_lib#
Overview#
llm_router_lib bundles Pydantic data‑model definitions and a thin, opinionated client wrapper for the
LLM‑Router service.
- The data models live in
llm_router_lib/data_modelsand describe every request payload the router accepts. - The client (
LLMRouterClient) offers a high‑level, Pythonic API that hides HTTP details, retries, and error handling. - Low‑level service classes (
ConversationWithModelService,ExtendedConversationWithModelService,TranslateService,GenerativeAnswerService, health services) perform the actual HTTP calls and can be used directly when finer‑grained control is required. HttpRequester(inutils/http.py) is a small wrapper aroundrequeststhat adds logging, configurable retries, and unified error translation.- A dedicated exception hierarchy (
exceptions.py) maps HTTP errors to meaningful Python exceptions.
In short, llm_router_lib provides both the contract (the “schema”) and a convenient client to consume the
router service.
Installation#
The library targets Python 3.10.6 and uses a virtualenv. Install it in editable mode for development:
# Clone the repository (if you haven't already)
git clone https://github.com/radlab-dev-group/llm-router.git
cd llm-router/llm_router_lib
# Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install the package and its dependencies
pip install -e .
All runtime dependencies (requests, pydantic, plus the packages listed in requirements.txt) are declared in the
project’s requirements.txt.
Quick start#
from llm_router_lib import LLMRouterClient
# Initialise the client – point it at the router’s host (do **not** include the `/api` prefix)
client = LLMRouterClient(
api="http://localhost:8080", # router host URL
token="YOUR_ROUTER_TOKEN", # optional, if router requires auth
)
# Call the standard conversation endpoint with named keyword arguments –
# the client builds the Pydantic request model for you.
response = client.conversation_with_model(
user_last_statement="Hello, how are you?",
model="google/gemma-3-12b-it",
temperature=0.7,
max_new_tokens=128,
)
# response is a typed `ConversationResponse` model:
print(response.response) # → the assistant's reply text
print(response.generation_time) # → seconds taken by the server
You can also pass a ready‑made pydantic request model via the payload
keyword (all endpoint parameters are keyword‑only – there are no positional arguments):
from llm_router_lib.data_models.builtin_chat import ConversationWithModelRequest
payload = ConversationWithModelRequest(
model_name="google/gemma-3-12b-it",
user_last_statement="Hello, how are you?",
temperature=0.7,
max_new_tokens=128,
)
response = client.conversation_with_model(payload=payload)
Note: raw
dictpayloads are no longer accepted – passing adictaspayloadraisesTypeError. Build the matching Pydantic model explicitly (e.g.ConversationWithModelRequest(**dict_payload)) or use the named keyword arguments. Calling a generation method with neitherpayloadnor enough named arguments raisesNoArgsAndNoPayloadError.
Data models#
All request payloads are defined in llm_router_lib/data_models.
A common base class supplies shared options:
class BaseModelOptions(BaseModel):
"""Options shared across many endpoint models."""
mask_payload: bool = False
masker_pipeline: Optional[List[str]] = None
Conversation models#
| Model | Required fields | Optional / extra fields |
|---|---|---|
ConversationWithModelRequest |
model_name, user_last_statement |
temperature, max_new_tokens, historical_messages, … |
ExtendedConversationWithModelRequest |
All of the above + system_prompt |
– |
Utility models (selected examples)#
| Model | Required fields | Optional fields (generation parameters) |
|---|---|---|
GenerateQuestionsModel |
texts + model_name |
number_of_questions, generation opts |
GenerateArticleFromTextModel |
text + model_name |
generation opts |
TranslateModel |
texts + model_name |
generation opts |
GenerativeAnswerModel |
question_str, texts + model_name |
doc_name_in_answer, question_prompt, system_prompt, generation opts |
OpenAIChatModel (OpenAI‑compatible) |
model, messages |
stream, keep_alive, language, options |
SimplifyTextModel |
texts, model_name |
generation opts |
CreateFullArticleFromTextsModel |
user_query, texts, model_name |
article_type, generation opts |
GenerateLabelModel |
texts + model_name |
generation opts |
(All utility models inherit from BaseModelOptions and therefore share the mask_payload and masker_pipeline
flags.)
Services (low‑level wrappers)#
If you need direct access to the HTTP layer, the library exposes a set of service classes in llm_router_lib/services:
| Service class | Endpoint (relative to api) |
Payload model (if any) |
|---|---|---|
ConversationWithModelService |
/api/conversation_with_model |
ConversationWithModelRequest |
ExtendedConversationWithModelService |
/api/extended_conversation_with_model |
ExtendedConversationWithModelRequest |
TranslateService |
/api/translate |
TranslateModel |
SimplifyTextService |
/api/simplify_text |
SimplifyTextModel |
GenerativeAnswerService |
/api/generative_answer |
GenerativeAnswerModel |
GenerateQuestionsService |
/api/generate_questions |
GenerateQuestionsModel |
GenerateLabelService |
/api/generate_label |
GenerateLabelModel |
PingService |
/api/ping |
none |
VersionService |
/api/version |
none |
These services inherit from BaseConversationServiceInterface, which provides call_post and call_get helpers that
perform JSON parsing and raise the library‑specific exceptions on failure.
Example: using a service directly#
from llm_router_lib.services.conversation import ConversationWithModelService
from llm_router_lib.utils.http import HttpRequester
import logging
http = HttpRequester(base_url="http://localhost:8080", token="...", timeout=10)
logger = logging.getLogger("demo")
service = ConversationWithModelService(http, logger)
payload = {
"model_name": "google/gemma-3-12b-it",
"user_last_statement": "Hi!",
}
response = service.call_post(payload)
print(response)
Thin client wrapper (LLMRouterClient)#
LLMRouterClient aggregates the low‑level services and exposes a concise, high‑level API:
Every endpoint method shares one keyword‑only calling contract: pass a pre‑built Pydantic request model via
payload=…, or pass the named domain arguments (plus model and optional temperature / max_new_tokens) and the
client builds the request model for you. Raw dict payloads are rejected (TypeError); generation defaults come from
the Pydantic models. Calling a generation method with neither payload nor enough named arguments raises
NoArgsAndNoPayloadError.
| Method | Endpoint | Domain arguments (all keyword‑only) |
|---|---|---|
conversation_with_model(...) |
POST /api/conversation_with_model |
user_last_statement, historical_messages, model, temperature, max_new_tokens |
extended_conversation_with_model(...) |
POST /api/extended_conversation_with_model |
user_last_statement, historical_messages, system_prompt, model, temperature, max_new_tokens |
polarity_3c(...) |
POST /api/polarity_3c |
texts, model, temperature, max_new_tokens |
translate(...) |
POST /api/translate |
texts, model, temperature, max_new_tokens |
simplify_text(...) |
POST /api/simplify_text |
texts, model, temperature, max_new_tokens |
generative_answer(...) |
POST /api/generative_answer |
texts, question_str, model, temperature, max_new_tokens |
generate_article_from_text(...) |
POST /api/generate_article_from_text |
text, model, temperature, max_new_tokens |
generate_article_from_texts(...) |
POST /api/generate_article_from_texts |
texts, model, temperature, max_new_tokens |
create_full_article_from_texts(...) |
POST /api/create_full_article_from_texts |
user_query, texts, article_type, model, temperature, max_new_tokens |
generate_questions(...) |
POST /api/generate_questions |
texts, number_of_questions, model, temperature, max_new_tokens |
generate_label(...) |
POST /api/generate_label |
texts, model, temperature, max_new_tokens |
ping() |
GET /api/ping |
– (health‑check endpoint) |
version() |
GET /api/version |
– (router version information) |
models() |
GET /v1/models |
– (available model list; use .ids / .data) |
Every method above also accepts payload=<RequestModel> as the alternative to the named arguments (e.g.
translate(payload=TranslateModel(...))).
All methods return a typed response model (a Pydantic BaseModel) validated from the JSON body — see
RESPONSE_MODELS.md for the full reference and the method→model mapping. Call
.model_dump() on the result to get the plain dict back. Errors from the underlying HTTP layer are translated into
the following exceptions (defined in exceptions.py):
LLMRouterError– base class for all library‑specific errors.AuthenticationError– HTTP 401/403 (invalid or missing token).RateLimitError– HTTP 429 (too many requests).ValidationError– HTTP 400 (malformed payload).NoArgsAndNoPayloadError– client‑side validation: raised when a generation method is called withoutpayloadand without enough named arguments.
:::tip Field naming across models
Models for the built‑in generative endpoints use model_name as the field key (e.g.
ConversationWithModelRequest). The OpenAI‑compatible endpoint model uses model instead, to match the official
OpenAI API schema:
| Model class | Key for model identifier |
|---|---|
ConversationWithModelRequest |
model_name |
OpenAIChatModel |
model |
:::
:::tip Context manager support
All public types (LLMRouterClient, HttpRequester) implement __enter__ / __exit__, so they can be used with
the
with statement to guarantee resource cleanup:
from llm_router_lib import LLMRouterClient
with LLMRouterClient(api="http://localhost:8080", token="...") as client:
result = client.conversation_with_model( # session closed automatically
user_last_statement="Hi!",
model="google/gemma-3-12b-it",
)
:::
Utilities#
-
utils/http.py–HttpRequester
Handles URL construction, bearer‑token injection, configurable retries (viaurllib3.Retry), and unified error mapping. It returns the rawrequests.Responseafter validation. -
exceptions.py– centralised exception definitions (see above).
Development & testing#
The repository includes a small test harness under llm_router_lib/tests. Example usage:
python -m llm_router_lib.tests.llm_router_client
This script spins up a LLMRouterClient instance and runs a suite of end‑to‑end tests covering conversation, extended
conversation, translation, generative answering, and health checks.