Dream Engines

AsyncClient

Async sibling of Client — same surface, await-driven. Use it for concurrent rollouts, agent loops, or any context where a blocking sync call would tie up an event loop.

Construction

PYTHON
import dream
async with dream.AsyncClient(
api_key="dre_...", # optional; reads DREAM_API_KEY
base_url="https://...", # optional; reads DREAM_BASE_URL
timeout_s=300.0,
retry_policy=dream.RetryPolicy(),
) as client:
...

The context manager closes the underlying httpx.AsyncClient on exit. You can also use it without a context manager and call await client.close() yourself.

Methods

Mirror of Client — every method is a coroutine:

PYTHON
await client.healthz()
await client.status()
async for handle in await client.models.list(): # not actually `async for`; .list returns list
...
model = await client.models.get("dreamdojo-2b-gr1")
rollout = await model.predict(start_frame=img, actions=actions)
batch = await model.predict_batch(start_frame=img, actions=k_seqs)

AsyncModelHandle.predict / .predict_batch accept the same arguments as the sync versions — full input coercion + validation runs before the network call.

Concurrent rollouts

The headline use case. K independent rollouts (different inputs) in parallel:

PYTHON
import asyncio, dream
async with dream.AsyncClient() as client:
model = await client.models.get("dreamdojo-2b-gr1")
rollouts = await asyncio.gather(*[
model.predict(start_frame=imgs[i], actions=acts[i])
for i in range(10)
])
for i, r in enumerate(rollouts):
r.save(f"rollout_{i:02d}.mp4")

Modal autoscales the engine container pool up to 8 concurrent rollouts; past 8, requests queue server-side. The SDK doesn't impose its own client-side concurrency cap — you can fire 100 in parallel and the server's queue + your retry policy will handle the rest.

For visual MPC where K candidates share one starting frame, prefer predict_batch over gather — the fused server-side forward is much cheaper than K independent rollouts.

Sync ↔ async

The two clients are independent — there's no "give me the async version of this sync Client" helper. Pick one for your codebase. Same api_key, same base_url, same engine.

If you need to mix (rare), construct both:

PYTHON
sync_client = dream.Client()
async_client = dream.AsyncClient()

They don't share a connection pool but they share the same retry policy semantics and error taxonomy.