Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/core/env_server/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
# LICENSE file in the root directory of this source tree.

from abc import ABC, abstractmethod
from typing import Any, Protocol, TypedDict
from typing import Any, List, Protocol, TypedDict

from .types import Action, Observation, State
from .types import Action, Observation, State, ToolDefinition


class Message(TypedDict):
Expand Down Expand Up @@ -116,3 +116,15 @@ def _apply_transform(self, observation: Observation) -> Observation:
if self.transform is not None:
return self.transform(observation)
return observation

def actions(self) -> List[ToolDefinition]:
"""Return list of available actions in this environment.

This method enables action discovery for any environment type.
Actions can represent tools, code execution, game moves, navigation,
or any domain-specific operations.

For backward compatibility, environments can return an empty list,
though implementing this method is strongly encouraged.
"""
return []
74 changes: 73 additions & 1 deletion src/core/env_server/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ class Action:
metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass(kw_only=True)
class ToolCallAction(Action):
"""Action representing a named operation with typed parameters.

Inspired by MCP's tool-calling pattern, but generalized to represent
ANY environment action - not just tool calls or code execution.

Examples:
- Tool calls: tool_name="search_web", parameters={"query": "..."}
- Code execution: tool_name="execute_code", parameters={"code": "..."}
- Game moves: tool_name="move_piece", parameters={"from": "e2", "to": "e4"}
- Navigation: tool_name="go_north", parameters={}
- Configuration: tool_name="set_timeout", parameters={"seconds": 30}

This is the standard action type for all OpenEnv environments.
Environments dispatch based on tool_name to handle different action types.
"""

tool_name: str
parameters: Dict[str, Any] = field(default_factory=dict)


@dataclass(kw_only=True)
class Observation:
"""Base class for all environment observations."""
Expand Down Expand Up @@ -48,10 +70,60 @@ class CodeExecResult:
@dataclass
class EnvironmentMetadata:
"""Metadata about an environment for documentation and UI purposes."""

name: str
description: str
readme_content: Optional[str] = None
version: Optional[str] = None
author: Optional[str] = None
documentation_url: Optional[str] = None


@dataclass
class ToolParameter:
"""Definition of a tool parameter."""

name: str
type: str # JSON Schema type: "string", "number", "boolean", "object", "array"
description: str
required: bool = True
default: Any = None


@dataclass
class ToolDefinition:
"""Specification of an action that can be taken in an environment.

Inspired by MCP's tool definition format and compatible with LLM tool-calling
APIs (Claude, OpenAI, etc.), but represents ANY action type - not just tools.

This can describe:
- External tool calls (search_web, read_file)
- Code execution (execute_python, run_bash)
- Game actions (move_piece, attack, defend)
- Navigation commands (go_north, turn_left)
- Configuration changes (set_parameter, update_config)
- Any domain-specific action
"""

name: str
description: str
parameters: List["ToolParameter"]

def to_json_schema(self) -> Dict[str, Any]:
"""Convert to JSON Schema format for LLM tool calling."""
return {
"name": self.name,
"description": self.description,
"input_schema": {
"type": "object",
"properties": {
p.name: {
"type": p.type,
"description": p.description,
}
for p in self.parameters
},
"required": [p.name for p in self.parameters if p.required],
},
}