Skip to navigation

nemo_gym.web.browser_instance

View as MarkdownOpen in Claude

One browser session per process, reachable over HTTP.

A headed PyAutoGUI driver acts on its process’s X display, so one process can serve one session at a time. A browser instance is such a process with its own display: it hosts an unmodified web backend (driver plus evaluator) behind six endpoints, and the resources server reaches it through RemoteWebBackend. The resources server can then hold as many sessions as it has instances, while every action still runs through the same driver code as a local session.

The server is single-threaded on purpose: Playwright’s synchronous API is thread-affine, so every backend call runs on the main thread.

Module Contents

Classes

NameDescription
BrowserInstanceUnavailableErrorThe instance could not be reached or answered outside its protocol.
RemoteWebBackendForward the web backend protocol to one leased browser instance.
_Conflict-
_InstanceState-

Functions

NameDescription
_load-
_make_handler-
_object_path-
_watch_parentExit when the pool that spawned this instance is gone.
main-
serve-

Data

DIRECT

LOG

TOKEN_ENV

TOKEN_HEADER

TRANSPORT

API

class nemo_gym.web.browser_instance.BrowserInstanceUnavailableError()

Bases: RuntimeError

The instance could not be reached or answered outside its protocol.

class nemo_gym.web.browser_instance.RemoteWebBackend(
config: typing.Any,
session_id: str,
backend_factory: str
)

Forward the web backend protocol to one leased browser instance.

Calls are synchronous and run on the session’s operation-runner thread, like the local backend they replace. The instance builds the real backend on reset from the factory and configuration named here, so the resources server and the instance always agree on driver and evaluator.

_endpoint
= handle.endpoint.rstrip('/')
_timeout
_token
= str(handle.metadata.get('token') or '')
nemo_gym.web.browser_instance.RemoteWebBackend._call(
path: str,
payload: dict[str, typing.Any]
) -> dict[str, typing.Any]
nemo_gym.web.browser_instance.RemoteWebBackend.close() -> None
nemo_gym.web.browser_instance.RemoteWebBackend.evaluate(
final_answer: str | None = None
nemo_gym.web.browser_instance.RemoteWebBackend.observe() -> nemo_gym.web.models.WebObservation
nemo_gym.web.browser_instance.RemoteWebBackend.reset(
) -> tuple[nemo_gym.web.models.WebObservation, dict[str, typing.Any]]
nemo_gym.web.browser_instance.RemoteWebBackend.step(
class nemo_gym.web.browser_instance._Conflict()

Bases: RuntimeError

class nemo_gym.web.browser_instance._InstanceState(
token: str
)
exit_code
int | None = None
session_id
str | None = None
nemo_gym.web.browser_instance._load(
path: str
) -> typing.Any
nemo_gym.web.browser_instance._make_handler(
) -> type[http.server.BaseHTTPRequestHandler]
nemo_gym.web.browser_instance._object_path(
value: typing.Any
) -> str
nemo_gym.web.browser_instance._watch_parent(
parent_pid: int
) -> None

Exit when the pool that spawned this instance is gone.

nemo_gym.web.browser_instance.main(
argv: list[str] | None = None
) -> int
nemo_gym.web.browser_instance.serve(
host: str,
port: int,
token: str,
parent_pid: int | None = None
) -> int
nemo_gym.web.browser_instance.DIRECT = urllib.request.build_opener(urllib.request.ProxyHandler({}))
nemo_gym.web.browser_instance.LOG = logging.getLogger('nemo_gym.web.browser_instance')
nemo_gym.web.browser_instance.TOKEN_ENV = 'NEMO_GYM_BROWSER_INSTANCE_TOKEN'
nemo_gym.web.browser_instance.TOKEN_HEADER = 'X-Browser-Instance-Token'
nemo_gym.web.browser_instance.TRANSPORT = 'browser_instance'