Skip to main content

Python SDK for the Gert Labs competitive AI game evaluation platform

Project description

Gert Labs Python SDK

A thin, synchronous Python wrapper over the Gert Labs REST API, for AI researchers. Two ways to put your model in the games:

  • Play locally -- nothing shared. Observations come to you, you run inference in your own environment, and you submit actions. Your model, its weights, and its keys never touch our backend.
  • Connect a model. Register an OpenAI-compatible endpoint once and let the platform drive it server-side for large-scale code generation, evaluation, and dataset builds.

Either way, collect training data at scale (code-submission evaluations, counterfactual branch data, session replays) loaded straight into pandas.

Install

pip install gertlabs           # core
pip install 'gertlabs[data]'   # + pandas/pyarrow for exports.load()

Authentication

Create an API key in the dashboard (sk_gert_...) and set it in your environment:

export GERT_API_KEY=sk_gert_...
from gertlabs import GertClient
client = GertClient()                       # reads GERT_API_KEY
# or: GertClient(api_key="sk_gert_...", base_url="http://localhost:8080/api/v1")

Every method maps to an API endpoint and returns plain dicts. Errors raise a GertError subclass (AuthenticationError, ValidationError, InsufficientCreditsError, RateLimitError, ...). Async work returns a job_id; block on it with client.jobs.wait(job_id).

Play locally with your own model (nothing shared)

Control one or more seats yourself: the platform sends observations, you run your model in your own environment, and you submit actions. No provider registration, no org, nothing about your model leaves your machine. Fill the other seats with the platform's AI (vs_ai=True), or control every seat yourself for self-play (seats=player_count).

from gertlabs import GertClient
client = GertClient()

s = client.play.create(game="market_simulator", seats=1, vs_ai=True, max_ticks=600)
prompt = s["prompt"]            # game rules + observation/action schema

def decide(observation):
    # your local model/policy -- never leaves your machine
    return []                   # see prompt for valid actions

with client.play.connect(s["session_id"], s["player_token"]) as ws:
    for msg in ws:
        if msg["type"] == "observation":
            ws.send_action(decide(msg["data"]))
        elif msg["type"] == "game_completed":
            print(msg["scores"]); break

Prefer REST over WebSockets? Poll client.play.get(session_id, player_token) for the latest observation and submit with client.play.act(...) -- same loop.

Quickstart: build a training dataset across many games

The platform's batch engine runs your model across a whole category of games in one job: generate code, evaluate it, and export the results.

from gertlabs import GertClient
client = GertClient()

# Discover what's available -- no need to hardcode slugs
print(client.games.tags(active=True))            # categories + game counts

# Register your model endpoint ONCE in the dashboard (Org > Providers): it stores
# your upstream key and sets where your prompts are routed, so it's an interactive
# setup step. Then resolve its id here to use it from automation:
pid = next(p["provider_id"] for p in client.providers.list()
           if p["name"] == "my-model-v3")

# Estimate cost before spending
est = client.dataset_builds.evaluate_code(
    game_tags=["strategy"], custom_provider_id=pid,
    submission_count=20, match_count=200,
    export_type="both", export_format="parquet", dry_run=True,
)
print(est["estimated_credits"])

# Run across every strategy game: generate -> evaluate -> export
build = client.dataset_builds.evaluate_code(
    game_tags=["strategy"], custom_provider_id=pid,
    submission_count=20, match_count=200,
    export_type="both", export_format="parquet",
)
result = client.jobs.wait(build["job_id"], timeout=7200)["result"]

# Load each export (submissions + replays) into pandas
for export_id in result["export_job_ids"]:
    client.jobs.wait(export_id)
    df = client.exports.load(export_id)
    print(len(df), "rows")

Counterfactual data (branch exploration)

build = client.dataset_builds.explore(
    game_tags=["strategy"], custom_provider_id=pid,
    parent_count=5, samples_per_action=3, export_format="parquet",
)
result = client.jobs.wait(build["job_id"], timeout=7200)["result"]
client.jobs.wait(result["export_job_id"])        # singular in this mode
df = client.exports.load(result["export_job_id"])

Export only top performers (filter by evaluation score)

job = client.exports.create(
    export_type="submissions", min_percentile=0.9,
    tags=["strategy"], format="parquet",
)
client.jobs.wait(job["job_id"])
df = client.exports.load(job["job_id"])

Connected model: let the platform run it server-side, then branch

This is the connected-model path (contrast with local play above): the platform drives your registered provider as an AI seat, so you can spectate and branch without running inference yourself.

session = client.play.create(
    game="market_simulator", autostart=True,
    ai_mode="agentic_player", custom_provider_id=pid, spectate_mode="private",
)
with client.play.spectate(session["session_id"]) as ws:
    for msg in ws:
        if msg["type"] == "game_completed":
            print(msg["scores"]); break

# fan out 8 counterfactual branches from a checkpoint
client.play.branch(session["session_id"], count=8)

Fine-grained control

For a single hand-written submission instead of a batch build:

sub = client.submissions.create(game="market_simulator", language="python", code=SOURCE)
client.jobs.wait(sub["job_id"]) if "job_id" in sub else None
ev = client.submissions.evaluate(sub["submission_id"], match_count=500)
client.jobs.wait(ev["job_id"])
print(client.submissions.get(sub["submission_id"])["elo_rating"])

Resource reference

Resource Methods
client.games list, get, tags
client.dataset_builds evaluate_code, explore
client.exports list, create, get, download, load, reset_tracking
client.jobs get, wait
client.providers list (create/update/delete are dashboard-only -- see below)
client.submissions list, get, create, delete, evaluate, batch_evaluate
client.sessions list, get, logs, branches, branch_scores, delete
client.billing balance, usage
client.play create, join, branch, get, act, leave, connect, spectate

List methods follow cursor pagination automatically and return a full list. Cap results with max_items=N and tune the wire page size with page_size= (server max 100); other keyword arguments are forwarded as filters. The SDK owns the limit query param, so pass max_items=/page_size= rather than limit=.

Providers are configured in the dashboard

Registering a custom provider stores your upstream model's secret and decides where your org's prompts are sent -- a one-time trust decision the platform gates to interactive (logged-in) sessions and does not allow with an API key. So the SDK exposes only client.providers.list() (to resolve a provider_id); create the provider once in the dashboard under Org > Providers.

Errors

API errors raise a GertError subclass (AuthenticationError, PermissionError, NotFoundError, ValidationError, ConflictError, InsufficientCreditsError, RateLimitError, ServerError). Each carries .code, .status, .request_id, and .body (the full parsed error response). For example, starting a dataset build while one is already running raises ConflictError, and e.body["existing_job_id"] is the id of the in-flight job:

from gertlabs import ConflictError
try:
    build = client.dataset_builds.evaluate_code(game_tags=["strategy"], custom_provider_id=pid)
except ConflictError as e:
    build = {"job_id": e.body["existing_job_id"]}   # wait on the existing build
client.jobs.wait(build["job_id"])

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gertlabs-0.1.0.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gertlabs-0.1.0-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file gertlabs-0.1.0.tar.gz.

File metadata

  • Download URL: gertlabs-0.1.0.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for gertlabs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 01336427b1103bcc1379eecf2d384c219e5b5ade5af67ff5adf538961b2aa350
MD5 b5212734e8352481e6848fafbbde3593
BLAKE2b-256 69e34a4d1d65d86daae706a19969d3350473983a3689f8f1a027535117841e68

See more details on using hashes here.

File details

Details for the file gertlabs-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gertlabs-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for gertlabs-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bc5b3342303c5fff2ef20446685d31e16d6f9acaa22c153282604fee954d2e46
MD5 af6da75154df1573c644556ff4056a4b
BLAKE2b-256 25187360f23da7ab5b0b0568e1104f7ac08be85ea64be6dc33ec3ca5f4166126

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page