openapp_env / client.py
Crashbandicoote2's picture
Upload folder using huggingface_hub
446b0a9 verified
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
"""
OpenApp Environment HTTP Client.
This module provides the client for connecting to an OpenApp Environment server
over HTTP.
"""
from typing import Any, Dict
# Support both in-repo and standalone imports
try:
# In-repo imports (when running from OpenEnv repository)
from core.client_types import StepResult
from core.env_server.types import State
from core.http_env_client import HTTPEnvClient
from .models import OpenAppAction, OpenAppObservation
except ImportError:
# Standalone imports (when environment is standalone with openenv-core from pip)
from openenv_core.client_types import StepResult
from openenv_core.env_server.types import State
from openenv_core.http_env_client import HTTPEnvClient
from openapp_env.models import OpenAppAction, OpenAppObservation
class OpenAppEnv(HTTPEnvClient[OpenAppAction, OpenAppObservation]):
"""
HTTP client for the OpenApp Environment.
This client connects to an OpenAppEnvironment HTTP server and provides
methods to interact with it: reset(), step(), and state access.
The OpenApp environment simulates web applications (calendar, todo, messenger, maps)
and allows agents to interact with them using browser-based actions.
Example:
>>> # Connect to a running server
>>> client = OpenAppEnv(base_url="http://localhost:8000")
>>> result = client.reset()
>>> print(result.observation.url)
>>>
>>> # Click on an element
>>> result = client.step(OpenAppAction(action_type="click", bid="123"))
>>> print(result.observation.html)
>>> print(result.reward)
Example with Docker:
>>> # Automatically start container and connect
>>> client = OpenAppEnv.from_docker_image("openapp-env:latest")
>>> result = client.reset()
>>> # Fill a text field
>>> result = client.step(OpenAppAction(
... action_type="fill",
... bid="456",
... text="Meeting with team"
... ))
"""
def _step_payload(self, action: OpenAppAction) -> Dict:
"""
Convert OpenAppAction to JSON payload for step request.
Args:
action: OpenAppAction instance
Returns:
Dictionary representation suitable for JSON encoding
"""
payload = {
"action_type": action.action_type,
}
# Add optional fields if present
if action.bid is not None:
payload["bid"] = action.bid
if action.text is not None:
payload["text"] = action.text
if action.value is not None:
payload["value"] = action.value
if action.url is not None:
payload["url"] = action.url
if action.direction is not None:
payload["direction"] = action.direction
if action.metadata:
payload["metadata"] = action.metadata
return payload
def _parse_result(self, payload: Dict) -> StepResult[OpenAppObservation]:
"""
Parse server response into StepResult[OpenAppObservation].
Args:
payload: JSON response from server
Returns:
StepResult with OpenAppObservation
"""
obs_data = payload.get("observation", {})
observation = OpenAppObservation(
html=obs_data.get("html", ""),
url=obs_data.get("url", ""),
open_pages_urls=obs_data.get("open_pages_urls", []),
active_page_index=obs_data.get("active_page_index", 0),
screenshot=obs_data.get("screenshot"),
axtree_txt=obs_data.get("axtree_txt", ""),
app_state=obs_data.get("app_state", {}),
task_info=obs_data.get("task_info"),
last_action_error=obs_data.get("last_action_error"),
done=payload.get("done", False),
reward=payload.get("reward"),
metadata=obs_data.get("metadata", {}),
)
return StepResult(
observation=observation,
reward=payload.get("reward"),
done=payload.get("done", False),
)
def _parse_state(self, payload: Dict) -> State:
"""
Parse server response into State object.
Args:
payload: JSON response from /state endpoint
Returns:
State object with episode_id and step_count
"""
return State(
episode_id=payload.get("episode_id"),
step_count=payload.get("step_count", 0),
)