Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions python/python/lance_context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

from .api import ( # pyright: ignore[reportMissingImports]
AsyncContext,
AsyncRolloutStore,
Context,
ContextNamespace,
EmbeddingProvider,
RemoteContext,
RemoteRolloutStore,
RolloutStore,
__version__,
)
Expand All @@ -16,12 +16,12 @@

__all__ = [
"AsyncContext",
"AsyncRolloutStore",
"Context",
"ContextNamespace",
"EmbeddingProvider",
"MultiModalEmbeddingProvider",
"RemoteContext",
"RemoteRolloutStore",
"RolloutStore",
"__version__",
]
16 changes: 9 additions & 7 deletions python/python/lance_context/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@

__all__ = [
"AsyncContext",
"AsyncRolloutStore",
"Context",
"ContextNamespace",
"EmbeddingProvider",
"RemoteContext",
"RemoteRolloutStore",
"RolloutStore",
"__version__",
]
Expand Down Expand Up @@ -2594,18 +2594,20 @@ def __repr__(self) -> str:
return f"RolloutStore(version={self._sync.version()})"


class RemoteRolloutStore:
"""Async wrapper around a remote rollout store over HTTP.
class AsyncRolloutStore:
"""Async wrapper around a rollout store, for use from asyncio code.

Mirrors :class:`RolloutStore` but runs the blocking calls in an executor so
they can be awaited. Every method matches its sync counterpart.
they can be awaited without blocking the event loop. Every method matches
its sync counterpart. This is the interface RL generation workers and the
learner use when talking to a remote ``lance-context-server`` over HTTP.
"""

def __init__(self, sync_store: _RolloutStore) -> None:
self._sync = sync_store

@classmethod
async def connect(cls, base_url: str, name: str) -> "RemoteRolloutStore":
async def connect(cls, base_url: str, name: str) -> "AsyncRolloutStore":
"""Connect to an existing remote rollout store."""
loop = asyncio.get_running_loop()
sync_store = await loop.run_in_executor(
Expand All @@ -2620,7 +2622,7 @@ async def connect_or_create(
name: str,
*,
storage_options: Mapping[str, str] | None = None,
) -> "RemoteRolloutStore":
) -> "AsyncRolloutStore":
"""Connect to a remote rollout store, creating it if absent."""
opts = dict(storage_options) if storage_options else None
loop = asyncio.get_running_loop()
Expand Down Expand Up @@ -2675,4 +2677,4 @@ async def checkout(self, version: int) -> None:
await loop.run_in_executor(None, lambda: self._sync.checkout(version))

def __repr__(self) -> str:
return f"RemoteRolloutStore(version={self._sync.version()})"
return f"AsyncRolloutStore(version={self._sync.version()})"
10 changes: 5 additions & 5 deletions python/tests/test_rollout_remote.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Remote (HTTP) rollout store tests.

Spins up a real `lance-context-server` subprocess and drives it through the
async `RemoteRolloutStore` wrapper — the path RL generation workers and the
async `AsyncRolloutStore` wrapper — the path RL generation workers and the
learner use in a deployed setup. Skips gracefully if the server binary has not
been built (e.g. a pure-Python CI job).
"""
Expand All @@ -18,7 +18,7 @@
from pathlib import Path

import pytest
from lance_context import RemoteRolloutStore
from lance_context import AsyncRolloutStore

_REPO_ROOT = Path(__file__).resolve().parents[2]
_SERVER_BIN = _REPO_ROOT / "target" / "debug" / "lance-context-server"
Expand Down Expand Up @@ -76,7 +76,7 @@ def server():

def test_remote_roundtrip(server):
async def run():
store = await RemoteRolloutStore.connect_or_create(server, "rl-run-1")
store = await AsyncRolloutStore.connect_or_create(server, "rl-run-1")

resp = await store.add(
[
Expand Down Expand Up @@ -119,12 +119,12 @@ async def run():

def test_remote_add_one_and_connect(server):
async def run():
store = await RemoteRolloutStore.connect_or_create(server, "rl-run-2")
store = await AsyncRolloutStore.connect_or_create(server, "rl-run-2")
await store.add_one(id="only", rollout_id="traj-9", reward=0.5)

# A second connection sees the first's flushed write (durable, no
# read affinity).
reader = await RemoteRolloutStore.connect(server, "rl-run-2")
reader = await AsyncRolloutStore.connect(server, "rl-run-2")
rows = await reader.list()
assert [r["id"] for r in rows] == ["only"]

Expand Down
Loading