galet
Provider-agnostic LLM, embedding, and image generation stack.
Lineage
This package is extracted from the Lucy monorepo (src/llm) as described in
the Lucy design doc software/ai/lucy/design/llm-module-extraction.md.
It is a fresh repository with no shared git history. The extracted module's
behaviour, public interface, optional-SDK import fallbacks, and
no-fail-on-missing-credential semantics are preserved as-is; the only
intentional change is the configuration boundary (see settings.py).
Features
- Chat / completions — provider-agnostic
create_responsewith temperature, tool calling, and response metadata. Providers: OpenAI, DeepSeek, Gemini, Mistral, Ollama. - Routing — explicit
providerargument, or automatic model-name prefix routing with OpenAI fallback. Source names, model-name prefixes, class paths, and default models are declarative; provider implementations load only when selected. - Model catalog — inspect source/model metadata and resolve a model from a profile, required capabilities, and optional model/source preferences.
- Tool calling — bounded tool loop; tools own
name(),tool_def(),result_schema(), andexecute(). - Image generation — OpenAI (
dall-e-*,gpt-image-*) and Gemini (gemini-*,imagen-*) backends behind a common interface. - Image description — vision-capable models describe images sent inline (base64, no upload).
- Embeddings — OpenAI and Mistral embedding adapters.
- Optional SDKs — imports degrade gracefully when a provider SDK is not installed; missing credentials never raise at import or call time.
Quick start
python -m venv .venv
.venv/bin/pip install -e .
Runnable examples live in samples/:
| Script | What it shows |
|---|---|
samples/send_request.py |
Simple chat request (defaults to local Ollama) |
samples/tool_handlers.py |
Tool-calling loop with a stubbed execute_command tool |
samples/generate_image.py |
Image generation via OpenAI or Gemini |
samples/describe_image.py |
Describe an image file with a vision model |
samples/list_sources.py |
List providers and model-prefix routing |
See samples/README.md for each script's full usage.
Configuration
galet needs two pieces of configuration, and both can be set with an environment variable or a command-line flag.
Credentials (API keys)
Galet owns provider credential resolution. Applications and delegated tasks should refer to a named profile rather than handle an API key.
A named profile selects exactly one source. Galet does not silently fall back to an environment variable or another file when that profile is selected.
from galet.settings import Settings
settings = Settings(
credential_profiles={
"openai-service": {
"provider": "openai",
"source": "file",
"path": "/etc/galet/credentials/oaicred.json",
}
},
credential_profile="openai-service",
)
key = settings.api_key("openai")
Supported profile sources:
| Source | Required field | Behaviour |
|---|---|---|
file |
path |
Reads the existing provider JSON credential format |
environment |
variable |
Reads only that named environment variable |
systemd |
credential |
Reads that file beneath CREDENTIALS_DIRECTORY |
Systemd credentials may contain the existing JSON object or the raw API key:
[Service]
User=lucy
LoadCredential=openai:/etc/galet/credentials/oaicred.json
settings = Settings(
credential_profiles={
"openai-service": {
"provider": "openai",
"source": "systemd",
"credential": "openai",
}
},
credential_profile="openai-service",
)
For ordinary protected files, keep credentials outside the repository, make
the directory accessible only to the service account, and make each credential
file readable only by that account. The GALET_CREDENTIAL_PATH environment
variable contains only a directory name and is not itself a secret.
For backward compatibility, when no named profile is selected Galet retains the original lookup order:
- The provider environment variable (
OPENAI_API_KEY,DEEPSEEK_API_KEY,GEMINI_API_KEY, orMISTRAL_API_KEY). - The provider file in
credential_pathorGALET_CREDENTIAL_PATH.
Credential file names and JSON keys:
| Provider | File | Key(s) in the file |
|---|---|---|
| openai | oaicred.json |
openai_api_key |
| deepseek | deepseek_cred.json |
deepseek_api_key |
| gemini | gemini_cred.json |
gemini_api_key, api_key |
| mistral | mistral_cred.json |
mistral_api_key |
Ollama base URL
Ollama needs no API key, but galet must know where the Ollama server is. galet resolves the address in this order:
--ollama-base-url(command-line flag)OLLAMA_BASE_URL(environment variable)http://localhost:11434/v1(default, Ollama's OpenAI-compatible endpoint)
# Default local Ollama
python samples/send_request.py --provider ollama "hi"
# Explicit URL
python samples/send_request.py --provider ollama --ollama-base-url http://localhost:11434/v1 "hi"
# Environment variable
OLLAMA_BASE_URL=http://192.168.87.40:11434/v1 python samples/send_request.py --provider ollama "hi"
Note the /v1 suffix: galet talks to Ollama's OpenAI-compatible endpoint, not
the native Ollama API.
Model information and capability resolution
ProviderRegistry continues to route explicit model names to their source.
Source and model metadata can be inspected without importing provider
implementations, making an API call, or reading credentials. ModelCatalog
adds deterministic capability-based selection.
from galet import ModelRequirements, default_model_catalog
for source in default_model_catalog.sources():
print(source.name, source.default_model)
for model in default_model_catalog.models(source="openai"):
print(model.name, sorted(model.profiles), sorted(model.capabilities))
resolved = default_model_catalog.resolve(
ModelRequirements.create(
profile="focused-development",
required_capabilities=("tool-calling", "code-generation"),
preferred_model="gpt-5-mini",
)
)
print(resolved.source, resolved.model)
Model preferences are not agent identities. A caller may request a capability profile and allow Galet to select an eligible fallback. Credential lookup remains inside Galet's provider settings and is not exposed by the catalog.
Release files for galet 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| galet-0.1.3.tar.gz | 55.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| galet-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 103.2 kB
Release files / galet-0.1.3.tar.gz
| Download URL | galet-0.1.3.tar.gz |
|---|---|
| Size | 55.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b66e4ef0cc7900bf07661ab27c4aac52ca27b05ddcdd3045be12a1bb0a716d09
|
|
BLAKE2b-256 checksum How to use checksums |
668121531633919c23f3557e5b2d73aa53ddfd1094f945ad9fdd50526828d1a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / galet-0.1.3-py3-none-any.whl
| Download URL | galet-0.1.3-py3-none-any.whl |
|---|---|
| Size | 47.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
08457cea855c145f7d3c7fe9db9b1a43778962d775edb436368db1176fbf47dd
|
|
BLAKE2b-256 checksum How to use checksums |
23f41e0939016a189b3bbc61121dd92ef8b78be3af6a5a89d8cbd9e5754c9605
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|