plato-sdk-v2 2.0.64__py3-none-any.whl → 2.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. plato/__init__.py +0 -9
  2. plato/_sims_generator/__init__.py +19 -4
  3. plato/_sims_generator/instruction.py +203 -0
  4. plato/_sims_generator/templates/instruction/helpers.py.jinja +161 -0
  5. plato/_sims_generator/templates/instruction/init.py.jinja +43 -0
  6. plato/agents/__init__.py +99 -430
  7. plato/agents/base.py +145 -0
  8. plato/agents/build.py +61 -0
  9. plato/agents/config.py +160 -0
  10. plato/agents/logging.py +515 -0
  11. plato/agents/runner.py +191 -0
  12. plato/agents/trajectory.py +266 -0
  13. plato/chronos/models/__init__.py +1 -1
  14. plato/sims/cli.py +299 -123
  15. plato/sims/registry.py +77 -4
  16. plato/v1/cli/agent.py +88 -84
  17. plato/v1/cli/pm.py +84 -44
  18. plato/v1/cli/sandbox.py +241 -61
  19. plato/v1/cli/ssh.py +16 -4
  20. plato/v1/cli/verify.py +685 -0
  21. plato/v1/cli/world.py +3 -0
  22. plato/v1/flow_executor.py +21 -17
  23. plato/v1/models/env.py +11 -11
  24. plato/v1/sdk.py +2 -2
  25. plato/v1/sync_env.py +11 -11
  26. plato/v1/sync_flow_executor.py +21 -17
  27. plato/v1/sync_sdk.py +4 -2
  28. plato/v2/__init__.py +2 -0
  29. plato/v2/async_/environment.py +31 -0
  30. plato/v2/async_/session.py +72 -4
  31. plato/v2/sync/environment.py +31 -0
  32. plato/v2/sync/session.py +72 -4
  33. plato/worlds/README.md +71 -56
  34. plato/worlds/__init__.py +56 -18
  35. plato/worlds/base.py +578 -93
  36. plato/worlds/config.py +276 -74
  37. plato/worlds/runner.py +475 -80
  38. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/METADATA +3 -3
  39. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/RECORD +41 -36
  40. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/entry_points.txt +1 -0
  41. plato/agents/callback.py +0 -246
  42. plato/world/__init__.py +0 -44
  43. plato/world/base.py +0 -267
  44. plato/world/config.py +0 -139
  45. plato/world/types.py +0 -47
  46. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/WHEEL +0 -0
plato/agents/build.py ADDED
@@ -0,0 +1,61 @@
1
+ """Build configuration for Plato agents.
2
+
3
+ Reads [tool.plato.build] from pyproject.toml to configure Docker builds.
4
+
5
+ Example pyproject.toml:
6
+ [tool.plato.build]
7
+ env = { "SOME_BUILD_ARG" = "value" }
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ from pydantic import BaseModel, Field
16
+
17
+ try:
18
+ import tomllib
19
+ except ImportError:
20
+ import tomli as tomllib
21
+
22
+
23
+ class BuildConfig(BaseModel):
24
+ """Docker build configuration for an agent.
25
+
26
+ Read from [tool.plato.build] in pyproject.toml.
27
+ """
28
+
29
+ env: dict[str, str] = Field(
30
+ default_factory=dict,
31
+ description="Environment variables to pass as build args",
32
+ )
33
+
34
+ def to_dict(self) -> dict[str, Any]:
35
+ """Convert to dict for schema output."""
36
+ return self.model_dump(exclude_defaults=False)
37
+
38
+ @classmethod
39
+ def get_json_schema(cls) -> dict[str, Any]:
40
+ """Get JSON schema for build config."""
41
+ schema = cls.model_json_schema()
42
+ schema.pop("title", None)
43
+ return schema
44
+
45
+ @classmethod
46
+ def from_pyproject(cls, path: str | Path) -> BuildConfig:
47
+ """Load build config from pyproject.toml."""
48
+ path = Path(path)
49
+ if path.is_dir():
50
+ path = path / "pyproject.toml"
51
+
52
+ with open(path, "rb") as f:
53
+ data = tomllib.load(f)
54
+
55
+ build_config = data.get("tool", {}).get("plato", {}).get("build", {})
56
+ return cls(**build_config)
57
+
58
+
59
+ def load_build_config(agent_path: str | Path) -> BuildConfig:
60
+ """Load build config from an agent directory."""
61
+ return BuildConfig.from_pyproject(agent_path)
plato/agents/config.py ADDED
@@ -0,0 +1,160 @@
1
+ """Typed configuration for Plato agents.
2
+
3
+ Provides base configuration classes that agents extend with their specific fields.
4
+ Secret fields are automatically loaded from environment variables using pydantic-settings.
5
+
6
+ Example:
7
+ from plato.agents import AgentConfig, Secret
8
+ from typing import Annotated
9
+
10
+ class OpenHandsConfig(AgentConfig):
11
+ model_name: str = "anthropic/claude-sonnet-4"
12
+ anthropic_api_key: Annotated[str | None, Secret(description="API key")] = None
13
+
14
+ # Secrets auto-loaded from env vars (ANTHROPIC_API_KEY -> anthropic_api_key)
15
+ config = OpenHandsConfig.from_file("/config.json")
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ from pydantic import Field
25
+ from pydantic_settings import BaseSettings, SettingsConfigDict
26
+
27
+
28
+ class Secret:
29
+ """Annotation marker for secret fields.
30
+
31
+ Fields annotated with Secret are automatically loaded from environment variables.
32
+ The env var name is the uppercase version of the field name (e.g., api_key -> API_KEY).
33
+
34
+ Usage:
35
+ api_key: Annotated[str, Secret(description="API key")]
36
+ """
37
+
38
+ def __init__(self, description: str = "", required: bool = False):
39
+ self.description = description
40
+ self.required = required
41
+
42
+
43
+ class AgentConfig(BaseSettings):
44
+ """Base configuration for agents.
45
+
46
+ Extends pydantic-settings BaseSettings, so secret fields are automatically loaded
47
+ from environment variables. The env var name is the uppercase field name.
48
+
49
+ Subclass with agent-specific fields:
50
+
51
+ class OpenHandsConfig(AgentConfig):
52
+ model_name: str = "anthropic/claude-sonnet-4"
53
+ anthropic_api_key: Annotated[str | None, Secret(description="API key")] = None
54
+
55
+ # ANTHROPIC_API_KEY env var is automatically loaded into anthropic_api_key
56
+ config = OpenHandsConfig.from_file("/config.json")
57
+
58
+ Attributes:
59
+ logs_dir: Directory for agent logs and trajectory output.
60
+ checkpoint_paths: Directories to watch for checkpoint triggers (for workspace tracking).
61
+ checkpoint_debounce_ms: Debounce interval for checkpoints.
62
+ """
63
+
64
+ model_config = SettingsConfigDict(
65
+ env_prefix="", # No prefix - ANTHROPIC_API_KEY maps to anthropic_api_key
66
+ extra="allow",
67
+ env_ignore_empty=True,
68
+ )
69
+
70
+ logs_dir: str = "/logs"
71
+ checkpoint_paths: list[str] = Field(default_factory=list)
72
+ checkpoint_debounce_ms: int = 500
73
+
74
+ @classmethod
75
+ def get_field_secrets(cls) -> dict[str, Secret]:
76
+ """Get Secret annotations for each field."""
77
+ result: dict[str, Secret] = {}
78
+
79
+ for field_name, field_info in cls.model_fields.items():
80
+ for meta in field_info.metadata:
81
+ if isinstance(meta, Secret):
82
+ result[field_name] = meta
83
+ break
84
+
85
+ return result
86
+
87
+ @classmethod
88
+ def get_json_schema(cls) -> dict:
89
+ """Get JSON schema with secrets separated."""
90
+ full_schema = cls.model_json_schema()
91
+ full_schema.pop("title", None)
92
+
93
+ secrets_map = cls.get_field_secrets()
94
+ properties = full_schema.get("properties", {})
95
+
96
+ config_properties = {}
97
+ secrets = []
98
+
99
+ # Skip internal fields
100
+ internal_fields = {"logs_dir", "checkpoint_paths", "checkpoint_debounce_ms"}
101
+
102
+ for field_name, prop_schema in properties.items():
103
+ if field_name in internal_fields:
104
+ continue
105
+
106
+ if field_name in secrets_map:
107
+ secret = secrets_map[field_name]
108
+ secrets.append(
109
+ {
110
+ "name": field_name,
111
+ "description": secret.description,
112
+ "required": secret.required,
113
+ }
114
+ )
115
+ else:
116
+ config_properties[field_name] = prop_schema
117
+
118
+ required = [r for r in full_schema.get("required", []) if r not in internal_fields and r not in secrets_map]
119
+
120
+ return {
121
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
122
+ "type": "object",
123
+ "properties": config_properties,
124
+ "required": required,
125
+ "secrets": secrets,
126
+ }
127
+
128
+ def get_secrets_dict(self) -> dict[str, str]:
129
+ """Extract secret values as a dict for environment variables."""
130
+ secrets_map = self.get_field_secrets()
131
+ result: dict[str, str] = {}
132
+
133
+ for field_name in secrets_map:
134
+ value = getattr(self, field_name, None)
135
+ if value is not None:
136
+ result[field_name] = value
137
+
138
+ return result
139
+
140
+ def get_config_dict(self) -> dict[str, Any]:
141
+ """Extract non-secret config values as a dict."""
142
+ secrets_map = self.get_field_secrets()
143
+ internal_fields = {"logs_dir", "checkpoint_paths", "checkpoint_debounce_ms"}
144
+
145
+ result: dict[str, Any] = {}
146
+ for field_name in self.model_fields:
147
+ if field_name not in secrets_map and field_name not in internal_fields:
148
+ value = getattr(self, field_name, None)
149
+ if value is not None:
150
+ result[field_name] = value
151
+
152
+ return result
153
+
154
+ @classmethod
155
+ def from_file(cls, path: str | Path) -> AgentConfig:
156
+ """Load config from a JSON file."""
157
+ path = Path(path)
158
+ with open(path) as f:
159
+ data = json.load(f)
160
+ return cls(**data)