RENAME
'jouleclaw-llm-cheap' implied a missing 'jouleclaw-llm-expensive'
counterpart. The crate's job is just 'the LLM dispatch tier' —
renamed to jouleclaw-llm.
All references updated: workspace member, Cargo.toml descriptions
in 7 consuming crates, use jouleclaw_llm:: in lib.rs files. Tier
description in workspace Cargo.toml now reads
'L3 LLM tier — sync trait surface, EchoBackend default'.
OPENAI-COMPATIBLE BACKEND — new module
One adapter covers a large fraction of the L3 LLM backend
landscape — every provider that speaks the OpenAI Chat
Completions wire format:
- OpenAI proper (api.openai.com)
- DeepSeek (api.deepseek.com)
- Together (api.together.xyz)
- Groq (api.groq.com/openai)
- Fireworks (api.fireworks.ai/inference)
- Mistral hosted (api.mistral.ai)
- vLLM local (localhost:8000)
- LM Studio (localhost:1234)
- LiteLLM proxy (operator's URL)
The transport carries the API key as a bearer token; this crate
hands the key string to the transport and lets it set the
Authorization header. Keeps jouleclaw-llm HTTP-client-agnostic.
OpenAiCompatibleBackend::new(transport, base_url, api_key, model)
OpenAiCompatibleBackend::openai(...)
OpenAiCompatibleBackend::deepseek(...)
OpenAiCompatibleBackend::together(...)
OpenAiCompatibleBackend::groq(...)
OpenAiCompatibleBackend::fireworks(...)
OpenAiCompatibleBackend::vllm_local(...)
with_typical_joules(j)
with_default_system(s)
Maps:
LlmRequest.system → message role=system
LlmRequest.prompt → message role=user
LlmRequest.max_tokens → max_tokens (omitted if 0)
LlmRequest.temperature → temperature
LlmRequest.stop → stop array
Response choices[0].finish_reason → FinishReason:
"stop" / "tool_calls" / "function_call" → Stop
"length" → Length
"content_filter" → ContentFilter
other non-empty → Error(other)
Usage fields → input_tokens / output_tokens.
energy_joules: None (OpenAI wire doesn't carry energy; cascade
falls back to typical_joules_per_call).
14 new tests covering URL construction, body shape (model,
messages, max_tokens, stop, system override and default),
response parsing (text + usage + all finish reasons),
error mapping (Unavailable for transport failures, Upstream for
non-JSON / error fields), and provider convenience constructors.
Total jouleclaw-llm tests: 53.
OPERATIONAL STATE
L3 LLM tier now has BOTH no-API (Ollama) and any-cloud
(OpenAI-compatible) backends in the same crate, behind the same
LlmBackend trait. A consumer picks at runtime: OllamaBackend for
the free path; OpenAiCompatibleBackend for any of the 9+
hosted/local OpenAI-compatible providers above.
cargo check --workspace --all-targets clean.
Co-Authored-By: Claude Opus 4.7 <[email protected]>