Spaces:
Running
Running
| #!/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"), | |
| ) | |