feat: add openai-compatible provider for custom AI endpoints

Add AI_PROVIDER=openai-compatible mode that reuses OpenAISynthesisProvider
with a validated custom base_url, allowing any OpenAI-compatible API
(OpenRouter, Ollama, LiteLLM proxy, etc.) without new code.

Configuration:
- AISettings.provider now accepts openai-compatible
- New AISettings.allow_insecure_http: bool = False (HTTP opt-in)
- .env.example: commented examples for OpenRouter (HTTPS) and Ollama (HTTP)

Factory validation (_validate_openai_compatible_config):
- base_url and model required, api_key required (MVP)
- HTTPS enforced unless allow_insecure_http=true
- Credentials in URL rejected, sensitive query params rejected
  (including valueless params via keep_blank_values=True)
- Malformed URLs and missing hostname rejected (ValueError caught)
- No /v1 manipulation; degraded to None + warning on invalid config
- redact_url() used for all URL warnings

Tests: 13 new factory tests in test_synthesis.py covering routing,
URL validation, HTTP policy, credentials, sentinel non-leak, no-network.
Coverage: 91.57% (synthesis module).

Docs: GUIDE_DEV_PYTHON.md §9.5 updated with 3-provider table, validation
rules, and synchronized code example.

mypy override for openai.* (follow_imports=skip) to work around
mypy 2.3.1 internal error in pre-commit's isolated environment.

Co-authored-by: opencode/coder anthropic.claude-sonnet-4-5 <anthropic.claude-sonnet-4-5@agents.invalid>
Co-authored-by: opencode/test-engineer anthropic.claude-sonnet-4-5 <anthropic.claude-sonnet-4-5@agents.invalid>
Co-authored-by: opencode/tech-writer anthropic.claude-sonnet-4-5 <anthropic.claude-sonnet-4-5@agents.invalid>
This commit is contained in:
2026-09-07 19:44:40 +02:00
parent 2a27225fa0
commit 13e058f22c
7 changed files with 378 additions and 6 deletions

View File

@@ -49,6 +49,20 @@ AI_BASE_URL=https://api.openai.com/v1
# AI_API_KEY=
# AI_MODEL=gpt-4o-mini # exemple recommandé, non activé par défaut
# Exemple : OpenRouter (HTTPS)
# AI_PROVIDER=openai-compatible
# AI_BASE_URL=https://openrouter.ai/api/v1
# AI_MODEL=fournisseur/modele
# AI_API_KEY=your-openrouter-key
# AI_ALLOW_INSECURE_HTTP=false
# Exemple : Ollama local (HTTP, sans authentification réelle)
# AI_PROVIDER=openai-compatible
# AI_BASE_URL=http://127.0.0.1:11434/v1
# AI_MODEL=modele-local
# AI_API_KEY=local-not-required
# AI_ALLOW_INSECURE_HTTP=true
# --- Blog ---
BLOG_ENABLED=false
BLOG_RSS_URL=https://blogpeda.ac-bordeaux.fr/cjeliote/?feed=rss2