git_env-v2-1-0 / client.py
burtenshaw's picture
burtenshaw HF Staff
Upload folder using huggingface_hub
459c40c verified
#!/usr/bin/env python3
"""
GitEnv Client
-------------
Client-side wrapper for the Git environment server.
This client maintains a persistent WebSocket connection to the environment
server, enabling efficient multi-step interactions with lower latency.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from openenv.core.client_types import StepResult
from openenv.core.env_client import EnvClient
from .models import GitAction, GitObservation, GitState
if TYPE_CHECKING:
from openenv.core.containers.runtime import ContainerProvider
class GitEnv(EnvClient[GitAction, GitObservation, GitState]):
"""
Client for Git Environment with Gitea server.
This client maintains a persistent WebSocket connection to the environment
server, enabling efficient multi-step interactions for Git operations.
The environment connects to a shared external Gitea service. Repositories
must be pre-migrated to Gitea before use.
Example:
>>> # From Docker image
>>> client = GitEnv.from_docker_image("git-env:latest")
>>> try:
... result = client.reset()
...
... # List available repositories
... from envs.git_env import GitAction
... result = client.step(GitAction(action_type="list_repos"))
... print(result.observation.repos)
...
... # Clone repository to workspace
... result = client.step(GitAction(action_type="clone_repo", repo_name="OpenEnv"))
...
... # Execute git commands
... result = client.step(GitAction(
... action_type="execute_git_command",
... command="status",
... working_dir="OpenEnv"
... ))
... finally:
... client.close()
"""
def _step_payload(self, action: GitAction) -> dict:
"""
Convert action to payload for server's /step endpoint.
Args:
action: GitAction to send to server
Returns:
Dictionary payload for HTTP request
"""
# Convert action to dictionary
payload = {
"action_type": action.action_type,
}
# Add type-specific fields for supported actions
if hasattr(action, "repo_name"):
payload["repo_name"] = action.repo_name
if hasattr(action, "target_dir"):
payload["target_dir"] = action.target_dir
if hasattr(action, "command"):
payload["command"] = action.command
if hasattr(action, "working_dir"):
payload["working_dir"] = action.working_dir
return payload
def _parse_result(self, payload: dict) -> StepResult[GitObservation]:
"""
Parse server response into StepResult.
Args:
payload: JSON response from /step endpoint
Returns:
StepResult containing GitObservation
"""
obs = GitObservation(**payload["observation"])
return StepResult(
observation=obs,
reward=payload.get("reward"),
done=bool(payload.get("done", False)),
)
def _parse_state(self, payload: dict) -> GitState:
"""
Parse server response into GitState object.
Args:
payload: JSON response from /state endpoint
Returns:
GitState object with environment state
"""
return GitState(
episode_id=payload.get("episode_id"),
step_count=payload.get("step_count", 0),
gitea_ready=payload.get("gitea_ready", False),
workspace_path=payload.get("workspace_path", "/workspace"),
)