DEV Community

Cover image for Build an OpenAI-compatible client that stops at the right time
Mattias chaw
Mattias chaw

Posted on Originally published at aiwave.live

Build an OpenAI-compatible client that stops at the right time

Build an OpenAI-compatible client that stops at the right time

An OpenAI-compatible route is only the beginning. A production client still needs a retry boundary, a response-shape check, and a receipt that can be reconciled without leaking a key.

This is a small Python pattern for https://aiwave.live/v1/chat/completions. It intentionally focuses on the part most integrations skip: deciding when to stop.

Architecture: application, recovery wrapper, AIWave, evidence record

The recovery contract

Condition Action
401, 402, malformed request, unknown status Stop. Do not guess or retry.
408, 429, 500, 502, 503, 504 Retry with a strict attempt cap.
200 without choices Reject it as incomplete.
usable 200 with usage Return a sanitized receipt.
RETRYABLE = {408, 429, 500, 502, 503, 504}

def request_chat(transport, payload, credential, max_attempts=3):
    if not credential:
        raise RuntimeError("missing credential")

    headers = {
        "Authorization": f"Bearer {credential}",
        "Content-Type": "application/json",
    }

    for attempt in range(1, max_attempts + 1):
        response = transport(payload, headers)
        status = response.get("status")
        body = response.get("body") or {}

        if status == 200:
            choices = body.get("choices")
            if not isinstance(choices, list) or not choices:
                raise RuntimeError("response missing choices")
            return {
                "model": body.get("model"),
                "content": (choices[0].get("message") or {}).get("content", ""),
                "usage": body.get("usage") or {},
                "attempts": attempt,
            }

        if status not in RETRYABLE or attempt == max_attempts:
            raise RuntimeError(f"request stopped at HTTP {status}")

    raise AssertionError("unreachable")
Enter fullscreen mode Exit fullscreen mode

Keep transport injected. You can now test failure behavior without a live credential:

$env:PYTHONPATH = (Resolve-Path 'api-recovery').Path
python -m unittest discover -s api-recovery/tests -v
Enter fullscreen mode Exit fullscreen mode

Decision flow: retry known transient failures, stop on unknown ones

The test suite covers a transient 503, immediate 401, incomplete 200, and an unknown status. The important property is not the number of retries. It is that each branch has an explicit terminal behavior.

A bounded live receipt

A privacy-safe record of model, tokens, elapsed time, charge, and assertion boundary

On 2026-10-19, one revocable-key non-streaming request was recorded in the AIWave Console with deepseek-v4-pro, 91 input / 16 output tokens, 2.0 seconds elapsed, and a $0.00024 request charge. That verifies one route and accounting path, not every model, account group, or workload.

The reply parsed, but a deliberately strict literal-content assertion did not match. The client stopped rather than retrying to obtain a prettier result. That is the behavior you want when a test tells you the response contract is not the contract you expected.

What to retain

Store only a small, sanitized receipt: model ID, status, attempt count, usage fields, elapsed time, and the request-level charge boundary. Keep API keys, full headers, private prompts, and account identifiers out of logs.

For async media routes, use a different contract: submission success is not terminal success. Poll, verify the stored result, and reconcile settlement before marking work complete.

Start with one request you can explain, then read the AIWave Chat Completions docs.

Top comments (0)