Catalog PyPI
PACKAGE EXPLORERView in registry

ai5labs-relay

PyPI

Official Python SDK for the Relay AI Gateway. One key, every model.

aiai-gatewayllmmulti-modelopentelemetryrelaysdkstreamingtool-calling
Versions collected1
Direct dependencies4From release 2.0.0
Last observed21 Oct, 09:49 UTC

README

Version 2.0.0 documentation

Relay AI SDK

Official Python SDK for the Relay AI Gateway. One key, every model.

pip install ai5labs-relay

With OpenTelemetry:

pip install ai5labs-relay[otel]

Quick start

from relay_ai import Relay

client = Relay(api_key="sk-relay-...")

response = client.chat("claude-sonnet-4.6", messages=[
    {"role": "user", "content": "Explain quantum computing in one sentence."}
])
print(response.text)
print(f"Tokens: {response.usage.total_tokens}")

Streaming

with client.chat("gemini-3.5-flash", messages=[
    {"role": "user", "content": "Write a haiku about code."}
], stream=True) as stream:
    for chunk in stream:
        print(chunk.text, end="", flush=True)

    final = stream.get_final_response()
    print(f"\nTokens: {final.usage.total_tokens}")

Async

from relay_ai import AsyncRelay

async with AsyncRelay() as client:
    response = await client.chat("claude-opus-4.8", messages=[
        {"role": "user", "content": "Hello!"}
    ])
    print(response.text)

Tool calling

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get current weather",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

response = client.chat("claude-sonnet-4.6", messages=[
    {"role": "user", "content": "What's the weather in Tokyo?"}
], tools=tools)

for tc in response.tool_calls:
    print(f"{tc.function_name}({tc.function_arguments})")

Image generation

result = client.images("flux-schnell", prompt="A cat astronaut on Mars")
print(result.images[0])

Audio

# Transcription
transcript = client.transcribe("whisper-1", "meeting.mp3")
print(transcript.text)

# Text-to-speech
audio = client.speech("tts-1", "Hello from Relay!")
with open("output.mp3", "wb") as f:
    f.write(audio.audio)

Semantic routing

decision = client.route(
    messages=[{"role": "user", "content": "Prove the Riemann hypothesis"}],
    candidates=["claude-opus-4.8", "claude-sonnet-4.6", "gemini-3.5-flash"],
)
print(f"Best model: {decision.alias} ({decision.confidence:.0%})")
print(f"Reasoning: {decision.reasoning}")

Batch processing

results = client.batch("claude-sonnet-4.6", [
    {"messages": [{"role": "user", "content": "What is 2+2?"}]},
    {"messages": [{"role": "user", "content": "What is 3+3?"}]},
    {"messages": [{"role": "user", "content": "What is 4+4?"}]},
], max_concurrent=5)

for r in results:
    if r.response:
        print(f"[{r.index}] {r.response.text}")
    else:
        print(f"[{r.index}] Error: {r.error}")

Credits

state = client.credits()
print(f"Balance: ${state.balance_cents / 100:.2f}")

Error handling

from relay_ai import (
    RelayError,
    AuthenticationError,
    RateLimitError,
    InsufficientCreditsError,
    ModelNotFoundError,
)

try:
    response = client.chat("gpt-5", messages=[...])
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except InsufficientCreditsError:
    print("Top up your credits at relay.ai5labs.com")
except ModelNotFoundError:
    print("Model not found")
except RelayError as e:
    print(f"Error: {e.message}")

CLI

export RELAY_API_KEY=sk-relay-...

relay models                                # List models
relay chat claude-sonnet-4.6 "Hello!"       # Quick chat
relay chat gemini-3.5-flash "Hi" --stream   # Stream tokens
relay credits                               # Check balance
relay version                               # SDK version

Configuration

client = Relay(
    api_key="sk-relay-...",       # or set RELAY_API_KEY env var
    base_url="https://...",       # custom gateway URL
    timeout=120.0,                # request timeout (seconds)
    max_retries=2,                # automatic retries on 429/5xx
    send_telemetry=True,          # usage analytics (metadata only)
    http_client=httpx.Client(),   # custom httpx client
)

Telemetry

The SDK sends anonymous usage metadata (model, token counts, latency) to improve the service. No message content, prompts, responses, or tool arguments are ever transmitted. This is enforced by a client-side allowlist and verified by server-side stripping.

Disable with:

client = Relay(send_telemetry=False)

OpenTelemetry

from relay_ai import Relay
from relay_ai._otel import instrument, RelaySpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider()
provider.add_span_processor(
    BatchSpanProcessor(
        RelaySpanExporter(api_key="sk-relay-...", base_url="https://api.relay.ai5labs.com/v1")
    )
)

client = instrument(Relay())
response = client.chat(...)  # Automatically creates OTel spans

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
2.0.0Yanked8 Jun 20264

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

ACCESSIBLE
ai5labs/relay-sdk

Shared repository data · GitHub

License detected in repository
Not collected
Last push
9 Jun 2026
Archived
No
Contributor identities
— · partial collection

Public sponsor counts have not been collected. These signals belong to the repository owner.

Downloads & popularity

0count
Gauge · observed snapshots24 Oct 2026
10.50
2026-10-24: 0 · observed 2026-10-24T10:56:49.8728295Z
24 Oct24 Oct

github · 1 observations shown. Missing days are unknown.

View observed values
Date / source periodValueObserved at
2026-10-2402026-10-24T10:56:49.8728295Z

Metadata history

Meaningful changes
Current collected state Current

Observed since 21 Oct, 09:49 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:bad54fc627c8232f7ca3c9591108bd818092c1a52d594ff78be108e8e47c6d25