Skip to main content

sidekick-sdk

CI PyPI Python License

Python client for the Sidekick Robotics API: one endpoint for every robotics foundation model, with routing, fallback and per-request billing.

pip install sidekick-sdk

One dependency (httpx). It installs on a robot control computer, or inside a ROS container, without dragging a web framework along.

Get an API key at sidekickrobotics.ai/api.

Sixty seconds

from sidekick_sdk import Sidekick

sk = Sidekick(api_key="sk-sidekick-...")

act = sk.act(
    model="sidekick/auto:manipulation",   # ask for a job, not a checkpoint
    observations=[sk.observation(image_path="frame.jpg", proprio=joints)],
    instruction="put the spoon on the towel",
    action_space="joint_pos_14",
    horizon=16,
)

print(act.route["model"])      # which checkpoint actually served you
print(act.usage["cost_usd"])   # what it cost
robot.execute(act.steps)

model takes a router alias (sidekick/auto:manipulation), a concrete model id, or a list via models=[...] in the order you want them tried. Every response carries route, so you always know what answered and whether it fell back.

Say what you care about

sk.act(..., preference="fastest")   # balanced | fastest | cheapest | reliable

fastest orders live candidates by measured latency, cheapest by price, reliable by success rate, balanced blends them. Add hard constraints alongside it:

sk.act(..., provider={"max_latency_ms": 900, "allow_simulated": False})

allow_simulated=False is the one to set for anything with an actuator behind it. Without it a placeholder response is structurally indistinguishable from a real one.

Four contracts, on purpose

Call Question it answers Returns
sk.predict() what happens next future frames
sk.act() what should I do next an action chunk
sk.ground() where is the thing boxes, masks, points
sk.evaluate() is this policy any good a benchmark job

They are not interchangeable, and the router will not silently serve one where you asked for another.

Control loops

The one thing that catches people: you cannot call a cloud API once per actuation. A control loop runs at 30 to 200 Hz and a policy answers in several hundred milliseconds. /v1/act therefore returns a chunk of N future actions plus the dt_ms they were planned for; the robot executes that chunk from a local buffer while the next one is fetched in the background.

ActionStream is that buffer, and the timing it gets right is not obvious:

stream = sk.stream_actions(
    model="sidekick/auto:manipulation",
    instruction="fold the towel",
    action_space="joint_pos_14", dof=14,
    preference="fastest",
    observe=lambda: sk.observation(cameras=rig.capture(), proprio=robot.joints()),
)

stream.warm_up()          # cold container, arm still braked
with stream:              # starts the background policy thread
    while running:
        step = stream.next_action()
        if step is None:
            robot.hold()  # policy fell behind; decelerate, never repeat
        else:
            robot.set_joint_positions(step)
        time.sleep(stream.dt_s)

Three things worth knowing about it:

  • next_action() never blocks and never raises. All network work happens on the policy thread. Your servo loop stays real-time.
  • None is a real answer. The buffer is dry or the chunk is stale. Hold or decelerate. Repeating the last command indefinitely is a robot acting on a world that has moved on.
  • Refills are triggered in time, not in steps. "Refetch when 5 steps are left" sounds right and stalls: 5 steps at 66 ms is 330 ms of runway against a 684 ms fetch. The stream measures its own round trip and refills at 1.5x it.

stream.check() runs three guards on every chunk before it can reach an actuator, raising UnsafeResponse on a simulated route, a mismatched action space, or a step whose width is not this robot's DOF.

Multi-camera rigs

obs = sk.observation(
    cameras={"cam_high": "frames/high.jpg",
             "cam_low": "frames/low.jpg",
             "cam_left_wrist": "frames/lw.jpg",
             "cam_right_wrist": "frames/rw.jpg"},
    proprio=joint_positions)

Values can be URLs, local paths or base64. Camera names must match what the checkpoint declares: a wrist view passed as the head view produces confident nonsense, and nothing in the response says so.

Discovery

sk.routes()                       # router aliases that are live right now
sk.models(domain="manipulation")  # the catalog
sk.taxonomy()                     # every value the filters accept, with counts
sk.action_space_dims("joint_pos_14")
sk.preview_route(model="sidekick/auto:manipulation", contract="act")  # free dry run
sk.usage()                        # your ledger

Call taxonomy() instead of hard-coding domain, family or action-space strings.

Configuration

Sidekick(api_key=..., base_url=..., timeout=120.0, max_retries=2)

base_url defaults to $SIDEKICK_ORIGIN, then to the public gateway. Point it at a private deployment without touching call sites.

Errors

SidekickError carries .status, .code and .body. UnsafeResponse is separate on purpose: a SidekickError means the call did not succeed and you should retry; an UnsafeResponse means the call succeeded and the answer is wrong for this robot, which is the more dangerous case because nothing about it looks broken.

Full API reference: https://www.sidekickrobotics.ai/api

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md.

License

Apache-2.0. See LICENSE.

Download files

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

Source Distribution

sidekick_sdk-0.1.0.tar.gz (19.8 kB view details)

Uploaded Source

Built Distribution

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

sidekick_sdk-0.1.0-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sidekick_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 19.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for sidekick_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ea94928e91603267e24cf69a80c3285fba135d2014c7bc1d787c065a9f25c970
MD5 a142f6d57655281378edd6bc3bdb70d7
BLAKE2b-256 29744d71587d356e9306722bfd998d59fb14fec231dc279c93a76562301aa3cd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: sidekick_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for sidekick_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d0d13f0e7c6ae3164269c812953526612898ad674d02af41c2939ca2cb78084f
MD5 c0f1029dba46222e928028bc1e272f9d
BLAKE2b-256 ff68053ba40c8f99e061f9c87a7f56b82b9776c4100b206700a4686bb1ab7b9f

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.2

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page