Proxy FastAPI pour cursor-agent compatible avec l'API OpenAI/ChatGPT.
Ce projet permet d'exposer cursor-agent via une API REST compatible avec l'API OpenAI, permettant ainsi d'utiliser cursor-agent avec n'importe quel client compatible OpenAI (comme les bibliothèques openai en Python, JavaScript, etc.).
Le diagramme ci-dessous illustre le flux de communication entre les différents composants du système :
sequenceDiagram
participant User as 👤 User/Client
participant Proxy as 🔄 cursor-openai-proxy<br/>(FastAPI)
participant Agent as 🤖 cursor-agent<br/>(CLI)
participant LLM as 🧠 LLM<br/>(GPT-5/Claude/Grok)
Note over User,LLM: Requête de chat completion
User->>Proxy: POST /v1/chat/completions<br/>{model: "gpt-4o", messages: [...]}
activate Proxy
Note over Proxy: 1. Authentification<br/>(API_KEY)
alt API_KEY invalide
Proxy-->>User: 401/403 Unauthorized
end
Note over Proxy: 2. Mapping du modèle<br/>gpt-4o → gpt-5
Proxy->>Agent: cursor-agent --model gpt-5 "user: Hello"
activate Agent
Note over Agent: Préparation de la requête<br/>avec CURSOR_API_KEY
Agent->>LLM: Appel API du LLM<br/>(GPT-5, Claude 4.5, etc.)
activate LLM
Note over LLM: Traitement de la requête
LLM-->>Agent: Réponse du modèle
deactivate LLM
Agent-->>Proxy: Texte de réponse
deactivate Agent
Note over Proxy: 3. Formatage OpenAI-compatible<br/>{id, object, choices, usage}
Proxy-->>User: 200 OK<br/>Response OpenAI-compatible
deactivate Proxy
Note over User,LLM: Streaming (optionnel)
User->>Proxy: POST /v1/chat/completions<br/>{stream: true, ...}
activate Proxy
Proxy->>Agent: cursor-agent --model gpt-5 "..."
activate Agent
Agent->>LLM: Appel API streaming
activate LLM
loop Tokens en streaming
LLM-->>Agent: Token chunk
Agent-->>Proxy: Token chunk
Proxy-->>User: SSE: data: {chunk}
end
LLM-->>Agent: [DONE]
deactivate LLM
Agent-->>Proxy: Fin du stream
deactivate Agent
Proxy-->>User: SSE: data: [DONE]
deactivate Proxy
Note over User,LLM: Liste des modèles
User->>Proxy: GET /v1/models
activate Proxy
Note over Proxy: Retourne 17 modèles<br/>(9 natifs + 8 alias)
Proxy-->>User: 200 OK<br/>{data: [models]}
deactivate Proxy
- User/Client : Application utilisant le client OpenAI Python, JavaScript, ou requêtes curl
- cursor-openai-proxy : Serveur FastAPI qui expose l'API compatible OpenAI
- Authentification via API_KEY
- Mapping automatique des modèles (gpt-4o → gpt-5, claude-3-5-sonnet → sonnet-4.5)
- Formatage des réponses au format OpenAI
- cursor-agent : CLI officiel de Cursor pour interagir avec les LLMs
- Utilise CURSOR_API_KEY pour l'authentification
- Supporte 9 modèles natifs : auto, composer-1, gpt-5, gpt-5-codex, sonnet-4.5, opus-4.1, grok, etc.
- LLM : Modèles de langage (GPT-5, Claude 4.5, Opus 4.1, Grok, etc.)
- Python 3.8+
- uv (gestionnaire de paquets moderne)
- just (command runner moderne)
- cursor-agent installé et accessible
# Sur macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Ou avec Homebrew
brew install uv
# Ou avec pip
pip install uv# Sur macOS/Linux
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s '--to ~/.local/bin'
# Ou avec Homebrew
brew install just
# Ou avec cargo
cargo install justPour développement local (mode CLI):
# Installation officielle de cursor-agent
curl https://cursor.com/install -fsS | bash
# Vérifier l'installation
cursor-agent --version
# Devrait afficher: 2025.11.06-8fe8a63 (ou version similaire)
# Vérifier que cursor-agent est dans le PATH
which cursor-agent
# Devrait afficher: /Users/VOTRE_USER/.local/bin/cursor-agentPour Docker:
cursor-agent est automatiquement installé dans le conteneur Docker (voir Dockerfile). Aucune installation locale n'est requise si vous utilisez uniquement Docker.
Alternative : Mode HTTP
Si vous ne souhaitez pas installer cursor-agent localement, vous pouvez utiliser le mode HTTP en configurant CURSOR_AGENT_MODE=http dans .env. Dans ce cas, cursor-agent n'est pas nécessaire.
Méthode recommandée (avec uv sync):
# Crée automatiquement le venv et installe toutes les dépendances
uv sync
# ou
just installMéthode alternative:
# Créer l'environnement virtuel
uv venv
# Activer l'environnement virtuel
source .venv/bin/activate # Sur macOS/Linux
# ou
.venv\Scripts\activate # Sur Windows
# Installer les dépendances
uv pip install -e .Avec just (recommandé pour les commandes):
just dev # Mode développement avec reload (port 8001)
just run # Mode production (port 8001)
just start # Démarrer en arrière-plan (daemon)
just stop # Arrêter le serveur
just status # Vérifier l'état du serveur
just logs # Voir les logs en temps réel
just # Voir toutes les commandes disponiblesAvec uv (recommandé - pas besoin d'activer le venv):
uv run python main.pyOu avec le script de démarrage:
./run.shOu avec Docker:
just docker-build
just docker-up
# ou
docker-compose up -dOu directement avec Python après activation du venv:
source .venv/bin/activate
python main.pyOu avec uvicorn directement:
uv run uvicorn main:app --host 0.0.0.0 --port 8001 --reloadLe serveur sera accessible sur http://localhost:8001 (local) ou http://localhost:8002 (Docker tests)
Une fois le serveur démarré, accédez à:
- Swagger UI:
http://localhost:8001/docs - ReDoc:
http://localhost:8001/redoc
Ou utilisez:
just docs # Ouvre automatiquement la documentation dans le navigateurUne collection Postman complète est disponible pour tester l'API :
- Fichier :
postman/Cursor-API-Proxy.postman_collection.json - Environnement :
postman/Local.postman_environment.json - Documentation :
postman/README.md
Import dans Postman :
- Ouvrez Postman
- Cliquez sur Import
- Sélectionnez
postman/Cursor-API-Proxy.postman_collection.json - (Optionnel) Importez aussi
postman/Local.postman_environment.json - Configurez la variable
api_keysi l'authentification est activée
Le proxy supporte tous les modèles disponibles dans cursor-agent et mappe automatiquement les noms de modèles OpenAI/Anthropic populaires.
| Modèle | Description |
|---|---|
default |
Modèle par défaut de cursor-agent (recommandé) |
gpt-5 |
GPT-5 d'OpenAI |
sonnet-4 |
Claude Sonnet 4 d'Anthropic |
sonnet-4-thinking |
Claude Sonnet 4 avec mode thinking |
Les noms de modèles OpenAI populaires sont automatiquement mappés vers gpt-5 :
| Alias OpenAI | Mappé vers |
|---|---|
gpt-4o |
gpt-5 |
gpt-4o-mini |
gpt-5 |
gpt-4-turbo |
gpt-5 |
gpt-4 |
gpt-5 |
gpt-3.5-turbo |
gpt-5 |
| Alias Anthropic | Mappé vers |
|---|---|
claude-3-5-sonnet-20241022 |
sonnet-4 |
claude-sonnet-4 |
sonnet-4 |
claude-sonnet-4.0 |
sonnet-4 |
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(
base_url="http://localhost:8001/v1",
api_key=os.getenv("API_KEY")
)
# Utiliser GPT-5 avec un nom OpenAI (mappé automatiquement)
response = client.chat.completions.create(
model="gpt-4o", # Sera mappé vers gpt-5
messages=[{"role": "user", "content": "Hello"}]
)
# Utiliser Claude Sonnet 4 avec un nom Anthropic
response = client.chat.completions.create(
model="claude-3-5-sonnet-20241022", # Sera mappé vers sonnet-4
messages=[{"role": "user", "content": "Hello"}]
)
# Utiliser directement un nom cursor-agent
response = client.chat.completions.create(
model="gpt-5", # Nom natif cursor-agent
messages=[{"role": "user", "content": "Hello"}]
)
# Utiliser le modèle par défaut
response = client.chat.completions.create(
model="default", # Laisse cursor-agent choisir
messages=[{"role": "user", "content": "Hello"}]
)Pour obtenir la liste complète des modèles supportés :
curl http://localhost:8001/v1/modelsOu en Python :
models = client.models.list()
for model in models.data:
print(f"- {model.id} (owned by {model.owned_by})")Endpoint principal compatible avec l'API OpenAI.
Requête:
{
"model": "gpt-4o",
"messages": [
{"role": "system", "content": "Tu es un assistant utile."},
{"role": "user", "content": "Bonjour, comment ça va?"}
],
"temperature": 0.7,
"max_tokens": 1000
}Réponse:
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1234567890,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Réponse de cursor-agent..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
}
}Endpoint pour le streaming (Server-Sent Events).
Liste les modèles disponibles.
Vérification de santé du service.
Méthode rapide (interactive):
just setup-env
# ou
./scripts/setup-env.shMéthode manuelle:
# Copier le fichier d'exemple
cp .env.example .env
# Éditer avec votre éditeur préféré
nano .env
# ou
code .envVariables essentielles à configurer:
-
Mode cursor-agent (
CURSOR_AGENT_MODE):cli: Utilise cursor-agent en ligne de commandehttp: Appelle une API HTTP cursor-agentlibrary: Utilise cursor-agent comme bibliothèque Python
-
Selon le mode choisi:
- CLI:
CURSOR_AGENT_CLI_PATH(chemin vers l'exécutable) - HTTP:
CURSOR_AGENT_HTTP_URL(URL de l'API)
- CLI:
-
Sécurité (production):
API_KEY: Clé API pour protéger VOTRE API proxy (générée par vous, pas liée à cursor-agent)
⚠️ Important:API_KEYprotège votre API proxy, pas cursor-agent. Si cursor-agent nécessite une authentification, voir SECURITY.md.
Voir CONFIGURATION.md pour le guide complet de configuration et INTEGRATION.md pour les détails sur l'intégration avec cursor-agent.
Dans le fichier main.py, les fonctions d'intégration peuvent être adaptées:
_call_cursor_agent_cli()- pour le mode CLI_call_cursor_agent_http()- pour le mode HTTP_call_cursor_agent_library()- pour le mode Library
Voir INTEGRATION.md pour les détails.
Installer le client OpenAI pour les exemples:
uv sync --extra examples
# ou
uv pip install openaiPuis utiliser:
from openai import OpenAI
import os
from dotenv import load_dotenv
# Charger les variables d'environnement depuis .env
load_dotenv()
# Configurer le client pour pointer vers votre proxy
client = OpenAI(
base_url="http://localhost:8001/v1", # Port 8001 pour le développement local
api_key=os.getenv("API_KEY") # API key pour l'authentification
)
# Utiliser comme avec OpenAI
response = client.chat.completions.create(
model="cursor-agent",
messages=[
{"role": "user", "content": "Bonjour!"}
]
)
print(response.choices[0].message.content)Exécuter l'exemple:
just example
# ou
uv run python example_usage.pyPour la production, ajoutez:
- Authentification (API keys) - configuré via
API_KEYdans.env - Rate limiting - middleware disponible (décommenter dans
main.py) - Validation supplémentaire des entrées
- Logging et monitoring
- HTTPS/TLS
Voir DEPLOYMENT.md pour les détails sur le déploiement sécurisé.
Ce projet dispose d'une architecture de tests complète à plusieurs niveaux :
Tests rapides des composants individuels (config, endpoints, middlewares) :
just test # Exécuter tous les tests unitaires
just test-cov # Avec rapport de couverture
just test-watch # Mode watch (redémarre automatiquement)Fichiers : tests/test_api.py, tests/test_config.py
Tests rapides qui lancent automatiquement le serveur FastAPI en Python :
just test-integration-localCaractéristiques :
- ✅ Lance/arrête automatiquement le serveur FastAPI
- ✅ Vérifie qu'aucun serveur n'est déjà sur le port 8001
- ✅ Utilise le client OpenAI Python officiel
- ✅ Tests d'authentification, modèles, chat, conversations
- ⚡ Rapide : ~21 secondes
- 🎯 Usage : Développement quotidien, CI/CD rapide
Fichier : tests/test_integration_local.py
Tests complets qui lancent automatiquement Docker Compose :
just test-integration-dockerCaractéristiques :
- ✅ Lance/arrête automatiquement Docker Compose
- ✅ Vérifie qu'aucun conteneur n'est déjà sur le port 8002
- ✅ Tests spécifiques Docker : cursor-agent installé, env vars, stabilité
- ✅ Valide l'environnement de production complet
- 🐳 Complet : ~39 secondes
- 🎯 Usage : Validation avant release, CI/CD production
Fichier : tests/test_integration_docker.py
Configuration Docker de test : docker-compose.test.yml
Tests manuels avec curl (nécessite un serveur déjà lancé) :
just test-integration-curlFichier : scripts/test_integration.sh
# Tous les tests d'intégration (local + docker)
just test-integration-all
# TOUS les tests (unitaires + intégration complète)
just test-allPour éviter les conflits et clarifier ce qui est testé :
- Port 8001 : Python local (dev + tests locaux)
- Port 8002 : Docker (tests uniquement)
tests/
├── test_api.py # Tests unitaires des endpoints
├── test_config.py # Tests unitaires de la configuration
├── test_integration_local.py # Tests d'intégration Python (8001)
├── test_integration_docker.py # Tests d'intégration Docker (8002)
└── test_integration_openai.py # Tests génériques OpenAI (ancien)
scripts/
└── test_integration.sh # Tests bash/curl
docker-compose.test.yml # Configuration Docker pour les tests
Pendant le développement :
just test-integration-local # Rapide, teste le code PythonAvant un commit/push :
just test-all # Tout : unitaires + local + dockerEn CI/CD :
# Tests rapides pour chaque commit
just test-integration-local
# Tests complets pour main/release
just test-integration-docker- Le comptage de tokens est approximatif (1 token ≈ 4 caractères)
- Pour un comptage précis, intégrez
tiktokenou une bibliothèque similaire - Le streaming est simulé - adaptez selon les capacités réelles de cursor-agent
# Voir toutes les commandes disponibles
just
# Installation et développement
just install # Installer les dépendances
just dev # Mode développement avec reload
just run # Mode production
# Tests
just test # Tests unitaires uniquement
just test-cov # Tests unitaires avec couverture
just test-integration-local # Tests d'intégration Python (port 8001, rapide)
just test-integration-docker # Tests d'intégration Docker (port 8002, complet)
just test-integration-all # Tous les tests d'intégration
just test-all # TOUS les tests (unitaires + intégration)
# Qualité de code
just format # Formater le code
just lint # Vérifier le code
just check # Format + lint
# Docker
just docker-build # Construire l'image Docker (tag: latest)
just docker-build-tagged # Construire l'image Docker avec tag versionné (version-cursor-agent-hash-git)
# Docker Compose
just docker-up # Démarrer avec Docker Compose (utilise .env complet)
just docker-compose-secure # Démarrer Docker Compose en mode SÉCURISÉ (avec API_KEY)
just docker-compose-insecure # Démarrer Docker Compose en mode NON SÉCURISÉ (sans API_KEY)
just docker-down # Arrêter Docker Compose
just docker-compose-down-secure # Arrêter Docker Compose (mode sécurisé)
just docker-compose-down-insecure # Arrêter Docker Compose (mode non sécurisé)
just docker-logs # Voir les logs Docker Compose
just docker-compose-logs-secure # Voir les logs (mode sécurisé)
just docker-compose-logs-insecure # Voir les logs (mode non sécurisé)
# Docker Run (sans docker-compose)
just docker-run-secure # Démarrer Docker Run en mode SÉCURISÉ (avec API_KEY)
just docker-run-insecure # Démarrer Docker Run en mode NON SÉCURISÉ (sans API_KEY)
just docker-run-down-secure # Arrêter Docker Run (mode sécurisé)
just docker-run-down-insecure # Arrêter Docker Run (mode non sécurisé)
just docker-run-down # Arrêter tous les conteneurs Docker Run
just docker-run-logs-secure # Voir les logs Docker Run (mode sécurisé)
just docker-run-logs-insecure # Voir les logs Docker Run (mode non sécurisé)
# Utilitaires
just clean # Nettoyer les fichiers générés
just info # Informations sur l'environnement
just example # Exécuter l'exemple
just health # Vérifier la santé du serveur
just docs # Ouvrir la documentation- Guide de démarrage rapide - Démarrage en 5 minutes
- Guide de configuration - Configuration détaillée du .env
- Guide d'intégration - Comment intégrer avec cursor-agent
- Guide de sécurité - Authentification et sécurité
- Guide de déploiement - Déploiement en production
- Guide Docker - Utilisation avec Docker
- Guide de performance - Analyse des performances et optimisations
- Processus persistant et sessions - Tests sur les processus persistants
- Guide des tests - Scripts de test et validation
- Prochaines étapes - Checklist et améliorations
- Points à améliorer - Améliorations suggérées
Les contributions sont les bienvenues! N'hésitez pas à ouvrir une issue ou une pull request.
MIT