Retour à l'accueil

Proxy API Claude pour OpenClaw : code et utilisation d'outils

Serveur proxy restaure l'accès à Claude dans openclaw après blocage Anthropic. Émulation navigateur avec curl_cffi, support utilisation d'outils via invites XML et correction automatique JSON. Code complet, config et intégration pour développeurs.

Restaurez Claude dans OpenClaw : proxy avec utilisation d'outils
Advertisement 728x90

# Proxy API Claude via session web : Intégration OpenClaw avec utilisation d'outils

Anthropic a bloqué l'utilisation de Claude dans les applications tierces comme OpenClaw. Les abonnés Pro (100 $/mois) ont reçu 100 $ de crédits d'utilisation supplémentaires, mais cela ne résout pas l'intégration d'agents. La solution ? Un serveur proxy qui imite une session navigateur Claude.ai avec une API compatible OpenAI. Cela permet d'exécuter Claude Sonnet/Opus dans OpenClaw avec un support complet des outils.

Développé en Python avec curl_cffi pour l'empreinte TLS Chrome. Les cookies et l'ID d'appareil proviennent de votre session active. Chaque requête lance une nouvelle conversation, diffusant les complétions via SSE.

Configuration de base de la session et des en-têtes

La session imite Chrome avec de vrais cookies navigateur. Testé avec le navigateur anti-détection Camoufox.

Google AdInline article slot
def make_session() -> cf_requests.Session:
    """Crée une nouvelle session curl_cffi avec empreinte TLS Chrome."""
    cookies = get_cookies()
    session = cf_requests.Session(impersonate=IMPERSONATE)
    session.cookies.update(cookies)
    return session

def get_headers(cookies: dict) -> dict:
    return {
        "User-Agent": (
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
        ),
        "Origin": "https://claude.ai",
        "Referer": "https://claude.ai/new",
        "anthropic-device-id": cookies.get("anthropic-device-id", ""),
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
    }

Logique des requêtes de complétion

  • POST vers /api/organizations/{org_id}/chat_conversations pour créer une conversation.
  • POST vers /chat_conversations/{conv_id}/completion avec text/event-stream.
def claude_complete(
    prompt: str,
    internal_model: str,
) -> Generator[str, None, None]:
    """Générateur synchrone qui produit les lignes SSE de la complétion claude.ai."""
    cookies = get_cookies()
    org_id = cookies["lastActiveOrg"]
    headers = get_headers(cookies)

    session = make_session()

    # 1. Créer la conversation
    r = session.post(
        f"https://claude.ai/api/organizations/{org_id}/chat_conversations",
        json={"uuid": None, "name": ""},
        headers=headers,
        timeout=15,
    )
    r.raise_for_status()
    conv_id = r.json()["uuid"]
    log.info(f"Conv créée : {conv_id} model={internal_model}")

    # 2. Diffuser la complétion
    payload = {
        "prompt": prompt,
        "model": internal_model,
        "timezone": "Europe/Moscow",
        "attachments": [],
        "files": [],
    }
    r2 = session.post(
        f"https://claude.ai/api/organizations/{org_id}/chat_conversations/{conv_id}/completion",
        json=payload,
        headers={**headers, "Accept": "text/event-stream"},
        stream=True,
        timeout=60,
    )
    r2.raise_for_status()
    for line in r2.iter_lines():
        yield line

Le serveur API utilise aiohttp avec des routes pour /v1/models, /v1/chat/completions, /health. Il s'exécute sur 127.0.0.1:8787.

def make_app() -> web.Application:
    app = web.Application()
    app.router.add_get("/v1/models", handle_models)
    app.router.add_get("/health", handle_health)
    app.router.add_post("/v1/chat/completions", handle_chat_completions)
    return app

Intégration OpenClaw

Configuration du fournisseur :

"claude-web": {
    "baseUrl": "http://127.0.0.1:8787/v1",
    "apiKey": "dummy",
    "api": "openai-completions",
    "models": [
      {
        "id": "claude-sonnet-4-6-web",
        "name": "Claude Sonnet 4.6 (Web)",
        "reasoning": false,
        "input": ["text"],
        "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0},
        "contextWindow": 200000,
        "maxTokens": 32000
      }
    ]
}

La génération de texte fonctionne directement. L'utilisation d'outils nécessite des ajustements.

Google AdInline article slot

Support des outils : Injection de prompt

Le prompt système force Claude à sortir les appels d'outils au format XML :

TOOL_SYSTEM_PROMPT = """Vous avez accès à des outils. Quand vous devez appeler un outil, sortez UNIQUEMENT le bloc d'appel d'outil — sans explication, sans texte avant ou après :

<tool_call>
{{
"name": "tool_name_here", "arguments": {{"param1": "value1", "param2": "value2"}}
}}
</tool_call>

RÈGLES :
- Le JSON dans <tool_call> doit être valide — pas de virgules en fin, pas de commentaires
- Vous pouvez sortir plusieurs blocs <tool_call> en séquence
- Après réception des blocs <tool_result>, continuez votre réponse normalement
- Si vous n'appelez pas d'outil, répondez normalement sans balises <tool_call>

Outils disponibles :
{tools_json}"""

L'analyse utilise des regex avec auto-corrections pour les erreurs JSON (virgules en fin, commentaires).

Gestion finale des appels et résultats d'outils

  • L'analyseur extrait les blocs <tool_call>, corrige le JSON, convertit au format OpenAI.
  • Les résultats d'outils injectés comme XML <tool_result id="...">contenu</tool_result> dans les messages utilisateur.
def parse_tool_calls(text: str) -> tuple[list[dict], str]:
    tool_calls = []
    for match in TOOL_CALL_RE.finditer(text):
        raw_json = match.group(1).strip()
        obj = None
        try:
            obj = json.loads(raw_json)
        except json.JSONDecodeError:
            fixed = _try_fix_json(raw_json)
            obj = json.loads(fixed)
        if obj:
            tool_calls.append({
                "id": f"call_{uuid.uuid4().hex[:12]}",
                "type": "function",
                "function": {
                    "name": obj.get("name", ""),
                    "arguments": json.dumps(obj.get("arguments", {})),
                },
            })
    remaining = TOOL_CALL_RE.sub("", text).strip()
    return tool_calls, remaining

def inject_tool_results(messages: list[dict], tools: list[dict]) -> list[dict]:
    # Convertit les tool_calls/résultats OpenAI en XML pour Claude
    # ... (logique de batching et génération XML)

Fonctionnalités clés

  • Compatibilité totale : API OpenAI avec utilisation d'outils pour OpenClaw/Claude Sonnet 4.6 (contexte 200k).
  • Mode furtif : curl_cffi + vrais cookies/ID appareil, TLS Chrome.
  • Auto-correction : Gère les glitches JSON courants de Claude (virgules en fin, commentaires).
  • Streaming : SSE depuis l'API web, nouvelle conversation par requête.
  • Limites : Reste dans l'abonnement Pro, pas d'utilisation supplémentaire.

Limites et améliorations

Dépend de la stabilité de l'API web Claude.ai. Problèmes potentiels :

Google AdInline article slot
  • Captchas sur le site.
  • Expiration de sessions.
  • Changements d'endpoints.

Solutions : Actualisation des cookies via automation, rotation d'ID appareil, gestion d'erreurs.

— Editorial Team

Advertisement 728x90

Lire ensuite