Skip to content

Commit f103c0c

Browse files
authored
Merge branch 'main' into skeleton
2 parents 853d5c4 + fd3f040 commit f103c0c

File tree

8 files changed

+194
-86
lines changed

8 files changed

+194
-86
lines changed

.gitignore

Lines changed: 4 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@ parts/
2020
sdist/
2121
var/
2222
wheels/
23+
pip-wheel-metadata/
2324
share/python-wheels/
2425
*.egg-info/
2526
.installed.cfg
2627
*.egg
2728
MANIFEST
2829

2930
# PyInstaller
30-
# Usually these files are written by a python script from a template
31-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
3231
*.manifest
3332
*.spec
3433

@@ -49,77 +48,8 @@ coverage.xml
4948
*.py,cover
5049
.hypothesis/
5150
.pytest_cache/
52-
cover/
53-
54-
# Translations
55-
*.mo
56-
*.pot
57-
58-
# Django stuff:
59-
*.log
60-
local_settings.py
61-
db.sqlite3
62-
db.sqlite3-journal
63-
64-
# Flask stuff:
65-
instance/
66-
.webassets-cache
67-
68-
# Scrapy stuff:
69-
.scrapy
70-
71-
# Sphinx documentation
72-
docs/_build/
73-
74-
# PyBuilder
75-
.pybuilder/
76-
target/
77-
78-
# Jupyter Notebook
79-
.ipynb_checkpoints
80-
81-
# IPython
82-
profile_default/
83-
ipython_config.py
84-
85-
# pyenv
86-
# For a library or package, you might want to ignore these files since the code is
87-
# intended to run in multiple environments; otherwise, check them in:
88-
# .python-version
89-
90-
# pipenv
91-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94-
# install all needed dependencies.
95-
#Pipfile.lock
96-
97-
# poetry
98-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99-
# This is especially recommended for binary packages to ensure reproducibility, and is more
100-
# commonly ignored for libraries.
101-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102-
#poetry.lock
103-
104-
# pdm
105-
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106-
#pdm.lock
107-
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108-
# in version control.
109-
# https://pdm.fming.dev/#use-with-ide
110-
.pdm.toml
111-
112-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113-
__pypackages__/
114-
115-
# Celery stuff
116-
celerybeat-schedule
117-
celerybeat.pid
118-
119-
# SageMath parsed files
120-
*.sage.py
121-
122-
# Environments
51+
52+
# Virtual environments
12353
.env
12454
.venv
12555
env/
@@ -128,16 +58,6 @@ ENV/
12858
env.bak/
12959
venv.bak/
13060

131-
# Spyder project settings
132-
.spyderproject
133-
.spyproject
134-
135-
# Rope project settings
136-
.ropeproject
137-
138-
# mkdocs documentation
139-
/site
140-
14161
# mypy
14262
.mypy_cache/
14363
.dmypy.json
@@ -175,4 +95,4 @@ Desktop.ini
17595
# Exclude anything containing "claude" (case-insensitive)
17696
*claude*
17797
*Claude*
178-
*CLAUDE*
98+
*CLAUDE*

pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[build-system]
2+
requires = ["setuptools>=45", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "envtorch"
7+
version = "0.1.0"
8+
requires-python = ">=3.8"
9+
dependencies = [
10+
"torch>=1.9.0",
11+
"numpy>=1.19.0",
12+
]
13+
14+
[tool.setuptools]
15+
package-dir = {"" = "src"}
16+
17+
[tool.setuptools.packages.find]
18+
where = ["src"]

src/core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
from .env import *
1111
from .docker import *
1212

13-
# Note: MCP module doesn't export anything yet
13+
# Note: MCP module doesn't export anything yet

src/core/base.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Abstract base classes for EnvTorch
2+
from __future__ import annotations
3+
4+
from abc import ABC, abstractmethod
5+
from typing import Generic, TypeVar
6+
7+
from .types import StepResult
8+
9+
# Generic type variables
10+
ActT = TypeVar("ActT") # Type for the action sent to the environment
11+
ObsT = TypeVar("ObsT") # Type for the observation returned by the environment
12+
13+
14+
class BaseEnv(ABC, Generic[ActT, ObsT]):
15+
"""
16+
Abstract base class for all environments.
17+
18+
Each environment must implement:
19+
- reset(): to initialize or reinitialize environment state
20+
- step(action): to execute an action and return results
21+
- close(): to release resources (containers, sessions, etc.)
22+
"""
23+
24+
@abstractmethod
25+
def reset(self) -> ObsT:
26+
"""
27+
Resets the environment to its initial state.
28+
29+
Returns:
30+
ObsT: The initial observation after resetting.
31+
"""
32+
raise NotImplementedError
33+
34+
@abstractmethod
35+
def step(self, action: ActT) -> StepResult[ObsT]:
36+
"""
37+
Performs one logical step in the environment.
38+
39+
Args:
40+
action (ActT): The action to perform in the environment.
41+
42+
Returns:
43+
StepResult[ObsT]: The resulting observation, reward, done flag, and info.
44+
"""
45+
raise NotImplementedError

src/core/types.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Type definitions for EnvTorch
2+
from dataclasses import dataclass
3+
from typing import Any, Generic, Optional, TypeVar
4+
5+
# Generic type for observations
6+
ObsT = TypeVar("ObsT") # TypeVar for typehinting in IDEs
7+
8+
9+
@dataclass
10+
class StepResult(Generic[ObsT]):
11+
"""
12+
Represents the result of one environment step.
13+
14+
Attributes:
15+
observation: The environment's observation after the action.
16+
reward: Scalar reward for this step (optional).
17+
done: Whether the episode is finished.
18+
"""
19+
20+
observation: ObsT
21+
reward: Optional[float] = None
22+
done: bool = False

src/envs/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88

99
from .coding import CodingEnv
1010

11-
__all__ = ["CodingEnv"]
11+
__all__ = ["CodingEnv"]

src/envs/coding_env/env.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
envs/coding_env/env.py
3+
--------------------------------
4+
Concrete environment implementation using the core BaseEnv.
5+
POC implementation runs code locally via subprocess that can be changed later.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
import subprocess
11+
from typing import Optional
12+
13+
from core.base import BaseEnv
14+
from core.types import StepResult
15+
16+
from .models import CodeAction, CodeObservation
17+
18+
19+
class CodingEnv(BaseEnv[CodeAction, CodeObservation]):
20+
"""
21+
Minimal Coding Environment.
22+
23+
POC behavior:
24+
- reset(): returns a fresh, empty observation (no persistent state).
25+
- step(action): runs Python code with `python -c` and returns stdout/stderr/exit_code.
26+
27+
Future swap:
28+
Replace _run_code_locally() with a call to your Docker/gateway backend without
29+
changing the public API.
30+
"""
31+
32+
def __init__(
33+
self,
34+
default_timeout_s: float = 10.0,
35+
python_executable: str = "python",
36+
):
37+
"""
38+
Args:
39+
default_timeout_s: Max seconds to allow code execution before timing out.
40+
python_executable: Interpreter to run (e.g., "python3", a venv path, etc.).
41+
"""
42+
self._default_timeout_s = float(default_timeout_s)
43+
self._python = python_executable
44+
45+
# --- BaseEnv interface ---
46+
47+
def reset(self) -> CodeObservation:
48+
# No state to clear in this POC; return an initial observation.
49+
return CodeObservation(stdout="", stderr="", exit_code=0)
50+
51+
def step(self, action: CodeAction) -> StepResult[CodeObservation]:
52+
if not isinstance(action, CodeAction):
53+
raise TypeError(f"Expected CodeAction, got {type(action)!r}")
54+
55+
# TODO: replace dummy response with the call to the code executor inside the container
56+
obs, timed_out = CodeObservation(stderr="", stdout="", exit_code=0), False
57+
58+
# Simple reward heuristic: success and no stderr -> 1.0 else 0.0
59+
reward: Optional[float] = (
60+
1.0 if (obs.exit_code == 0 and not obs.stderr) else 0.0
61+
)
62+
63+
info = {
64+
"timed_out": timed_out,
65+
"interpreter": self._python,
66+
}
67+
68+
return StepResult(
69+
observation=obs,
70+
reward=reward,
71+
done=False, # Coding env is not episodic by default
72+
)

src/envs/coding_env/models.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
envs/coding_env/models.py
3+
--------------------------------
4+
Action/Observation types for the Coding environment.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
from dataclasses import dataclass
10+
from typing import Any, Optional
11+
12+
13+
@dataclass
14+
class CodeAction:
15+
"""
16+
Represents a single code execution request.
17+
"""
18+
19+
code: str
20+
# Optional: future fields like 'lint': bool, 'timeout_s': float, etc.
21+
22+
23+
@dataclass
24+
class CodeObservation:
25+
"""
26+
Result of executing code in the environment.
27+
"""
28+
29+
stdout: str = ""
30+
stderr: str = ""
31+
exit_code: int = 0

0 commit comments

Comments
 (0)