Integration¶
How to wire lexvault into a LiteLLM proxy deployment.
Prerequisites¶
- LiteLLM proxy (
litellm --config ...), version>=1.80.15(the iterator-hook dispatcher fix, PR #17626). - Python
>=3.10. - lexvault installed (
pip install lexvault) in the same environment as the proxy.
Mount the shim¶
LiteLLM's guardrail loader does a naive guardrail.split(".") and loads
<file>.py from the config directory (guardrail_registry.py). A pip-installed
package can't be referenced directly, so you mount a one-line shim next to your
config.yaml:
Reference it as guardrail: lexvault_shim.LexVaultGuardrail. Every existing
third-party LiteLLM guardrail ships this shim.
Minimal config¶
model_list:
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
guardrails:
- guardrail_name: lexvault
litellm_params:
guardrail: lexvault_shim.LexVaultGuardrail
mode: [pre_call, post_call]
default_on: true
dictionary_path: /app/dictionary.yaml
org_key: os.environ/LEXVAULT_ORG_KEY
Docker¶
See the examples directory
for a docker-compose.yml that volume-mounts config.yaml, lexvault_shim.py,
and dictionary.yaml into a lexvault-enabled LiteLLM image.
Per-request config¶
Override config per request (without premium features) via metadata and/or
headers. lexvault reads both locations defensively because the metadata
variable name is route-dependent in LiteLLM:
| Route | Metadata location |
|---|---|
/v1/messages, /v1/responses, batches, files |
data["litellm_metadata"] |
/v1/chat/completions (and everything else) |
data["metadata"] |
Scope override¶
curl http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "x-lexvault-scope: team-alpha" \
-d '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Project Titan"}],
"metadata": {"requester_metadata": {"lexvault_scope": "team-alpha"}}
}'
Supported keys: lexvault_scope (or header x-lexvault-scope).
Note
extra_body / get_guardrail_dynamic_request_body_params is enterprise-premium-gated
in LiteLLM and unusable for an OSS tool. lexvault uses the non-premium
metadata/headers channel only.
Guardrail ordering¶
LiteLLM runs guardrails in config-list order. If you run lexvault alongside a
one-way MASK guardrail (e.g. litellm_content_filter with action: MASK),
list lexvault FIRST so it masks before the one-way masker — otherwise the
one-way masker can destroy a term lexvault intended to reversibly map.
guardrails:
- guardrail_name: lexvault
litellm_params: # FIRST — reversible mask
guardrail: lexvault_shim.LexVaultGuardrail
mode: [pre_call, post_call]
default_on: true
# ...lexvault params...
- guardrail_name: content-filter
litellm_params: # after — one-way filter
guardrail: litellm_content_filter
mode: [pre_call, post_call]
default_on: true
# ...content-filter params...
Protected endpoints¶
Only the unified routes are protected:
-
/v1/chat/completions -
/v1/messages -
/v1/responses
Provider-prefixed passthrough routes bypass ALL guardrail hooks (they stream
via PassThroughStreamingHandler.chunk_processor):
-
/anthropic/... -
/openai/... -
/azure/...
Do not use passthrough routes if you need masking.
Non-text call types¶
lexvault safely no-ops (skip + debug log) on non-text call types: embeddings,
image_generation, transcription, rerank, speech, moderation. With
default_on: true the guardrail runs on all call types, but non-text ones are
detected and skipped.
Logging¶
lexvault's async_logging_hook re-masks the standard logging payload before
LiteLLM emits it to Langfuse/DataDog/OTel — originals never appear in logs, even
on the spend-logging path. This is defense-in-depth: the request is already
masked by pre_call, but the logging hook guards against any path that re-reads
raw kwargs/results.
Fail-open by design (CS-E9): the logging hook itself fails open — if its
re-mask raises, the un-re-masked payload is returned rather than crashing the
call. This is a deliberate never-crash tradeoff: the request is already masked
by pre_call, so a logging-hook failure cannot leak an original on the request
path (only a defense-in-depth layer is skipped). It is strictly weaker than
fail-closed masking, but crashing the proxy on a logging error is worse.
Deferred-logging dedup (CS-C9): on LiteLLM ≥1.83, the logging hook is invoked with a deduplicated payload (LiteLLM avoids double-logging the same event); on earlier versions it may fire twice. Both are benign — re-masking is idempotent.