plato-sdk-v2 2.1.15__py3-none-any.whl → 2.1.17__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.
plato/worlds/__init__.py CHANGED
@@ -1,7 +1,8 @@
1
1
  """Plato Worlds - typed world definitions for agent execution.
2
2
 
3
3
  Usage:
4
- from plato.worlds import BaseWorld, RunConfig, Agent, Secret, AgentConfig, register_world
4
+ from plato.worlds import BaseWorld, RunConfig, Agent, Secret, Env, AgentConfig, EnvConfig, register_world
5
+ from plato._generated.models import EnvFromArtifact, EnvFromSimulator
5
6
  from typing import Annotated
6
7
 
7
8
  class CodeWorldConfig(RunConfig):
@@ -15,6 +16,12 @@ Usage:
15
16
  # Secrets (typed)
16
17
  git_token: Annotated[str | None, Secret(description="GitHub token")] = None
17
18
 
19
+ # Environments (typed)
20
+ gitea: Annotated[EnvConfig, Env(description="Git server")] = EnvFromArtifact(
21
+ artifact_id="abc123",
22
+ alias="gitea",
23
+ )
24
+
18
25
  @register_world("code")
19
26
  class CodeWorld(BaseWorld[CodeWorldConfig]):
20
27
  name = "code"
@@ -25,11 +32,17 @@ Usage:
25
32
  url = self.config.repository_url
26
33
  agent = self.config.coder
27
34
  token = self.config.git_token
35
+ gitea = self.config.gitea # EnvConfig
28
36
 
29
37
  async def step(self) -> StepResult:
30
38
  ...
31
39
  """
32
40
 
41
+ from plato._generated.models import (
42
+ EnvFromArtifact,
43
+ EnvFromResource,
44
+ EnvFromSimulator,
45
+ )
33
46
  from plato.worlds.base import (
34
47
  BaseWorld,
35
48
  ConfigT,
@@ -39,7 +52,7 @@ from plato.worlds.base import (
39
52
  get_world,
40
53
  register_world,
41
54
  )
42
- from plato.worlds.config import Agent, AgentConfig, RunConfig, Secret
55
+ from plato.worlds.config import Agent, AgentConfig, Env, EnvConfig, RunConfig, Secret
43
56
  from plato.worlds.runner import run_world
44
57
 
45
58
  __all__ = [
@@ -56,6 +69,12 @@ __all__ = [
56
69
  "AgentConfig",
57
70
  "Agent",
58
71
  "Secret",
72
+ "Env",
73
+ "EnvConfig",
74
+ # Env types (re-exported from generated models)
75
+ "EnvFromArtifact",
76
+ "EnvFromSimulator",
77
+ "EnvFromResource",
59
78
  # Runner
60
79
  "run_world",
61
80
  ]
plato/worlds/base.py CHANGED
@@ -11,6 +11,7 @@ from pydantic import BaseModel, Field
11
11
  from plato.worlds.config import RunConfig
12
12
 
13
13
  if TYPE_CHECKING:
14
+ from plato.v2.async_.environment import Environment
14
15
  from plato.v2.async_.session import Session
15
16
 
16
17
  from plato.agents.logging import init_logging as _init_chronos_logging
@@ -193,6 +194,38 @@ class BaseWorld(ABC, Generic[ConfigT]):
193
194
  except Exception as e:
194
195
  self.logger.warning(f"Error stopping Plato heartbeat: {e}")
195
196
 
197
+ def get_env(self, alias: str) -> Environment | None:
198
+ """Get an environment by alias.
199
+
200
+ Use this to access environments defined in the world config (e.g., gitea, localstack).
201
+
202
+ Args:
203
+ alias: The environment alias (e.g., "gitea", "localstack", "runtime")
204
+
205
+ Returns:
206
+ The Environment object or None if not found or session not connected.
207
+
208
+ Example:
209
+ gitea = self.get_env("gitea")
210
+ if gitea:
211
+ result = await gitea.execute("git status")
212
+ """
213
+ if not self.plato_session:
214
+ self.logger.warning("Cannot get env: Plato session not connected")
215
+ return None
216
+ return self.plato_session.get_env(alias)
217
+
218
+ @property
219
+ def envs(self) -> list[Environment]:
220
+ """Get all environments in the Plato session.
221
+
222
+ Returns:
223
+ List of Environment objects. Empty list if session not connected.
224
+ """
225
+ if not self.plato_session:
226
+ return []
227
+ return self.plato_session.envs
228
+
196
229
  async def run(self, config: ConfigT) -> None:
197
230
  """Run the world: reset -> step until done -> close.
198
231
 
plato/worlds/config.py CHANGED
@@ -3,12 +3,20 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from pathlib import Path
6
- from typing import Any
6
+ from typing import Any, Union
7
7
 
8
8
  from pydantic import BaseModel, Field
9
9
 
10
+ from plato._generated.models import (
11
+ EnvFromArtifact,
12
+ EnvFromResource,
13
+ EnvFromSimulator,
14
+ )
10
15
  from plato.v2.async_.session import SerializedSession
11
16
 
17
+ # Union type for environment configurations
18
+ EnvConfig = Union[EnvFromArtifact, EnvFromSimulator, EnvFromResource]
19
+
12
20
 
13
21
  class AgentConfig(BaseModel):
14
22
  """Configuration for an agent.
@@ -46,10 +54,28 @@ class Secret:
46
54
  self.required = required
47
55
 
48
56
 
57
+ class Env:
58
+ """Annotation marker for environment fields.
59
+
60
+ Environments are VMs that run alongside the world's runtime.
61
+ They can be specified by artifact ID, simulator name, or resource config.
62
+
63
+ Usage:
64
+ gitea: Annotated[EnvConfig, Env(description="Git server")] = EnvFromArtifact(
65
+ artifact_id="abc123",
66
+ alias="gitea",
67
+ )
68
+ """
69
+
70
+ def __init__(self, description: str = "", required: bool = True):
71
+ self.description = description
72
+ self.required = required
73
+
74
+
49
75
  class RunConfig(BaseModel):
50
76
  """Base configuration for running a world.
51
77
 
52
- Subclass this with your world-specific fields, agents, and secrets:
78
+ Subclass this with your world-specific fields, agents, secrets, and envs:
53
79
 
54
80
  class CodeWorldConfig(RunConfig):
55
81
  # World-specific fields
@@ -62,6 +88,12 @@ class RunConfig(BaseModel):
62
88
  # Secrets (typed)
63
89
  git_token: Annotated[str | None, Secret(description="GitHub token")] = None
64
90
 
91
+ # Environments (typed)
92
+ gitea: Annotated[EnvConfig, Env(description="Git server")] = EnvFromArtifact(
93
+ artifact_id="abc123",
94
+ alias="gitea",
95
+ )
96
+
65
97
  Attributes:
66
98
  session_id: Unique Chronos session identifier
67
99
  callback_url: Callback URL for status updates
@@ -79,16 +111,16 @@ class RunConfig(BaseModel):
79
111
  model_config = {"extra": "allow"}
80
112
 
81
113
  @classmethod
82
- def get_field_annotations(cls) -> dict[str, Agent | Secret | None]:
83
- """Get Agent/Secret annotations for each field."""
84
- result: dict[str, Agent | Secret | None] = {}
114
+ def get_field_annotations(cls) -> dict[str, Agent | Secret | Env | None]:
115
+ """Get Agent/Secret/Env annotations for each field."""
116
+ result: dict[str, Agent | Secret | Env | None] = {}
85
117
 
86
118
  for field_name, field_info in cls.model_fields.items():
87
119
  marker = None
88
120
 
89
121
  # Pydantic stores Annotated metadata in field_info.metadata
90
122
  for meta in field_info.metadata:
91
- if isinstance(meta, (Agent, Secret)):
123
+ if isinstance(meta, (Agent, Secret, Env)):
92
124
  marker = meta
93
125
  break
94
126
 
@@ -98,7 +130,7 @@ class RunConfig(BaseModel):
98
130
 
99
131
  @classmethod
100
132
  def get_json_schema(cls) -> dict:
101
- """Get JSON schema with agents and secrets separated."""
133
+ """Get JSON schema with agents, secrets, and envs separated."""
102
134
  # Get full Pydantic schema
103
135
  full_schema = cls.model_json_schema()
104
136
  full_schema.pop("title", None)
@@ -110,6 +142,7 @@ class RunConfig(BaseModel):
110
142
  world_properties = {}
111
143
  agents = []
112
144
  secrets = []
145
+ envs = []
113
146
 
114
147
  # Skip runtime fields
115
148
  runtime_fields = {"session_id", "callback_url", "all_secrets", "plato_session"}
@@ -136,6 +169,26 @@ class RunConfig(BaseModel):
136
169
  "required": marker.required,
137
170
  }
138
171
  )
172
+ elif isinstance(marker, Env):
173
+ # Get default value for this env field
174
+ field_info = cls.model_fields.get(field_name)
175
+ default_value = None
176
+ if field_info and field_info.default is not None:
177
+ # Serialize the default EnvConfig to dict
178
+ default_env = field_info.default
179
+ if hasattr(default_env, "model_dump"):
180
+ default_value = default_env.model_dump()
181
+ elif isinstance(default_env, dict):
182
+ default_value = default_env
183
+
184
+ envs.append(
185
+ {
186
+ "name": field_name,
187
+ "description": marker.description,
188
+ "required": marker.required,
189
+ "default": default_value,
190
+ }
191
+ )
139
192
  else:
140
193
  world_properties[field_name] = prop_schema
141
194
 
@@ -149,8 +202,26 @@ class RunConfig(BaseModel):
149
202
  "required": required,
150
203
  "agents": agents,
151
204
  "secrets": secrets,
205
+ "envs": envs,
152
206
  }
153
207
 
208
+ def get_envs(self) -> list[EnvConfig]:
209
+ """Get all environment configurations from this config.
210
+
211
+ Returns:
212
+ List of EnvConfig objects (EnvFromArtifact, EnvFromSimulator, or EnvFromResource)
213
+ """
214
+ annotations = self.get_field_annotations()
215
+ envs: list[EnvConfig] = []
216
+
217
+ for field_name, marker in annotations.items():
218
+ if isinstance(marker, Env):
219
+ value = getattr(self, field_name, None)
220
+ if value is not None:
221
+ envs.append(value)
222
+
223
+ return envs
224
+
154
225
  @classmethod
155
226
  def from_file(cls, path: str | Path) -> RunConfig:
156
227
  """Load config from a JSON file."""
@@ -177,6 +248,9 @@ class RunConfig(BaseModel):
177
248
  # Handle secrets dict -> individual secret fields
178
249
  secrets_dict = data.pop("secrets", {})
179
250
 
251
+ # Handle envs dict -> individual env fields
252
+ envs_dict = data.pop("envs", {})
253
+
180
254
  # Merge world_config into top-level
181
255
  parsed.update(world_config)
182
256
  parsed.update(data)
@@ -191,8 +265,24 @@ class RunConfig(BaseModel):
191
265
  parsed[field_name] = AgentConfig(image=str(agent_data))
192
266
  elif isinstance(marker, Secret) and field_name in secrets_dict:
193
267
  parsed[field_name] = secrets_dict[field_name]
268
+ elif isinstance(marker, Env) and field_name in envs_dict:
269
+ env_data = envs_dict[field_name]
270
+ if isinstance(env_data, dict):
271
+ parsed[field_name] = _parse_env_config(env_data)
272
+ else:
273
+ parsed[field_name] = env_data
194
274
 
195
275
  # Store all secrets for agent use
196
276
  parsed["all_secrets"] = secrets_dict
197
277
 
198
278
  return cls(**parsed)
279
+
280
+
281
+ def _parse_env_config(data: dict) -> EnvConfig:
282
+ """Parse an env config dict into the appropriate type."""
283
+ if "artifact_id" in data:
284
+ return EnvFromArtifact(**data)
285
+ elif "sim_config" in data:
286
+ return EnvFromResource(**data)
287
+ else:
288
+ return EnvFromSimulator(**data)
plato/worlds/runner.py CHANGED
@@ -3,13 +3,15 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import json
6
7
  import logging
8
+ import os
7
9
  from pathlib import Path
8
10
  from typing import Annotated
9
11
 
10
12
  import typer
11
13
 
12
- from plato.worlds.config import RunConfig
14
+ from plato.worlds.config import EnvConfig, RunConfig
13
15
 
14
16
  app = typer.Typer(
15
17
  name="plato-world-runner",
@@ -133,6 +135,123 @@ def list_worlds(
133
135
  typer.echo(f" {name} (v{version}): {desc}")
134
136
 
135
137
 
138
+ async def _run_dev(
139
+ world_name: str,
140
+ config_path: Path,
141
+ env_timeout: int = 600,
142
+ ) -> None:
143
+ """Run a world locally with automatic environment creation.
144
+
145
+ This mimics what Chronos does but runs locally for debugging:
146
+ 1. Load and parse the config
147
+ 2. Create Plato session with all environments
148
+ 3. Run the world with the session attached
149
+ """
150
+ from plato.v2 import AsyncPlato
151
+ from plato.worlds.base import get_world
152
+
153
+ discover_worlds()
154
+
155
+ world_cls = get_world(world_name)
156
+ if world_cls is None:
157
+ from plato.worlds.base import get_registered_worlds
158
+
159
+ available = list(get_registered_worlds().keys())
160
+ raise ValueError(f"World '{world_name}' not found. Available: {available}")
161
+
162
+ # Load config
163
+ config_class = world_cls.get_config_class()
164
+ with open(config_path) as f:
165
+ config_data = json.load(f)
166
+
167
+ # Parse the config to get typed access
168
+ run_config = config_class._from_dict(config_data.copy())
169
+
170
+ # Get environment configs from the parsed config
171
+ env_configs: list[EnvConfig] = run_config.get_envs()
172
+
173
+ # Create Plato client
174
+ plato = AsyncPlato()
175
+ session = None
176
+
177
+ try:
178
+ if env_configs:
179
+ logger.info(f"Creating {len(env_configs)} environments...")
180
+ session = await plato.sessions.create(envs=env_configs, timeout=env_timeout)
181
+ logger.info(f"Created Plato session: {session.session_id}")
182
+ logger.info(f"Environments: {[e.alias for e in session.envs]}")
183
+
184
+ # Serialize and add to config
185
+ serialized = session.dump()
186
+ run_config.plato_session = serialized
187
+ else:
188
+ logger.info("No environments defined for this world")
189
+
190
+ # Run the world
191
+ logger.info(f"Starting world '{world_name}'...")
192
+ world_instance = world_cls()
193
+ await world_instance.run(run_config)
194
+
195
+ finally:
196
+ # Cleanup
197
+ if session:
198
+ logger.info("Closing Plato session...")
199
+ await session.close()
200
+ await plato.close()
201
+
202
+
203
+ @app.command("dev")
204
+ def dev(
205
+ world: Annotated[str, typer.Option("--world", "-w", help="World name to run")],
206
+ config: Annotated[Path, typer.Option("--config", "-c", help="Path to config JSON file")],
207
+ env_timeout: Annotated[int, typer.Option("--env-timeout", help="Timeout for environment creation (seconds)")] = 600,
208
+ verbose: Annotated[bool, typer.Option("--verbose", "-v", help="Enable verbose logging")] = False,
209
+ ) -> None:
210
+ """Run a world locally for development/debugging.
211
+
212
+ This creates Plato environments automatically (like Chronos does)
213
+ and runs the world with the session attached.
214
+
215
+ Example config.json:
216
+ {
217
+ "repository_url": "https://github.com/user/repo",
218
+ "prompt": "Fix the bug in main.py",
219
+ "agents": {
220
+ "coder": {
221
+ "image": "openhands:latest",
222
+ "config": {"model_name": "claude-sonnet-4"}
223
+ }
224
+ },
225
+ "secrets": {
226
+ "anthropic_api_key": "sk-..."
227
+ }
228
+ }
229
+
230
+ Environment variables:
231
+ PLATO_API_KEY: API key for Plato (required)
232
+ """
233
+ # Setup logging
234
+ log_level = logging.DEBUG if verbose else logging.INFO
235
+ logging.basicConfig(
236
+ level=log_level,
237
+ format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
238
+ )
239
+
240
+ if not config.exists():
241
+ typer.echo(f"Error: Config file not found: {config}", err=True)
242
+ raise typer.Exit(1)
243
+
244
+ if not os.environ.get("PLATO_API_KEY"):
245
+ typer.echo("Error: PLATO_API_KEY environment variable required", err=True)
246
+ raise typer.Exit(1)
247
+
248
+ try:
249
+ asyncio.run(_run_dev(world, config, env_timeout))
250
+ except Exception as e:
251
+ logger.exception(f"World execution failed: {e}")
252
+ raise typer.Exit(1)
253
+
254
+
136
255
  def main() -> None:
137
256
  """CLI entry point."""
138
257
  app()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plato-sdk-v2
3
- Version: 2.1.15
3
+ Version: 2.1.17
4
4
  Summary: Python SDK for the Plato API
5
5
  Author-email: Plato <support@plato.so>
6
6
  License-Expression: MIT
@@ -283,10 +283,13 @@ plato/_generated/api/v2/user/get_current_user.py,sha256=tvamtbWTEkeeNUBLSPqZIcCG
283
283
  plato/_generated/api/version/__init__.py,sha256=dQXTYrXjD1RZcvWwnlqXWAZ-eAV-V-6JSNuY7uaca7o,70
284
284
  plato/_generated/api/version/check.py,sha256=HTVNw0oi9gbvX4pOVoH4y4JywCxdl1pJTCk2PjJFwJ4,778
285
285
  plato/_generated/models/__init__.py,sha256=VGsTMYUCCqa7r_tl5m--dwjy7viYAN20nU2HhVAibcU,154130
286
- plato/_sims_generator/__init__.py,sha256=Cg8atlEoWsd5nf0qLz3_EbHxFVFtBwPDDUZbx3jxRrc,1125
286
+ plato/_sims_generator/__init__.py,sha256=Km4QOl9wxjQ5dgpdhk9QnBFJFFc9eq3rPbMWIQRjIn0,1602
287
287
  plato/_sims_generator/cli.py,sha256=mzolN-dxfMkVAdA-vC0esnai-cGg-i4ozOw8dACefV4,2709
288
+ plato/_sims_generator/instruction.py,sha256=cxRCsvJ92DJdTxpJcW7gUgL8kWM4abcjPZjLQMkgOhs,6575
288
289
  plato/_sims_generator/parser.py,sha256=BbgRYllqYf7H76JyMfe7LYo1we-kh7YEOxUwrYT3shc,38347
289
290
  plato/_sims_generator/python.py,sha256=ZYZJeOhGhYV95iB2_G-stQHaIv5sQj0jo3GXSLb6SdA,18295
291
+ plato/_sims_generator/templates/instruction/helpers.py.jinja,sha256=kJ8lhVLPygjMh8l-In9rLtFci6Bxg3zVoz5BZFfLKms,4937
292
+ plato/_sims_generator/templates/instruction/init.py.jinja,sha256=oabz8xKdkz9SjRBYwg_GoHZdz1ZrhHXOOEazw2pOczQ,879
290
293
  plato/_sims_generator/templates/python/api_init.py.jinja,sha256=HYNtVsiGU91IzhBtBA3qlLv8b3U5kZbmW-FqdZ9F7mQ,188
291
294
  plato/_sims_generator/templates/python/client.py.jinja,sha256=H99L4kgRfTwJs3DOC9P-DcGtHNYBDNxcOvtedWEgWYM,19755
292
295
  plato/_sims_generator/templates/python/endpoint.py.jinja,sha256=1ToZiS8w_aZydVBhNt5KxLIbCo3toWCi4NPjLAmhVy4,12478
@@ -299,7 +302,7 @@ plato/agents/base.py,sha256=vUbPQuNSo6Ka2lIB_ZOXgi4EoAjtAD7GIj9LnNotam0,4577
299
302
  plato/agents/build.py,sha256=CNMbVQFs2_pYit1dA29Davve28Yi4c7TNK9wBB7odrE,1621
300
303
  plato/agents/config.py,sha256=VZVMdCmEQnoR0VkrGdScG8p6zSKVFe7BZPd2h8lKNjI,5460
301
304
  plato/agents/logging.py,sha256=z9rDlGPbrpcTS8PephbK2rDqT7thC1KyLkua4ypUkv4,12210
302
- plato/agents/runner.py,sha256=rW46kigbbC66OQsn6QBoSuDENpLCrIK0K-SuF67JWUs,4599
305
+ plato/agents/runner.py,sha256=rOWYTSAhdola_FdrbviP955NBusNtBUy-q_c5fDA9to,5123
303
306
  plato/agents/trajectory.py,sha256=ayXEMCfYvIuXU2JkQWfPOVO9JywNSx8Kf6Ztrgsdh-I,10441
304
307
  plato/chronos/__init__.py,sha256=RHMvSrQS_-vkKOyTRuAkp2gKDP1HEuBLDnw8jcZs1Jg,739
305
308
  plato/chronos/client.py,sha256=YcOGtHWERyOD9z8LKt8bRMVL0cEwL2hiAP4qQgdZlUI,5495
@@ -373,9 +376,9 @@ plato/chronos/models/__init__.py,sha256=Iyh5srlL4oqsviCnjk9xHW7g0BjgJR4lAthFkZoX
373
376
  plato/sims/README.md,sha256=FIbJhNVNAV-SO6dq_cXX3Rg0C7HdQCfEY9YxGlkCmsM,6902
374
377
  plato/sims/__init__.py,sha256=tnoCGKZwNx6h22tEWLujdpLv6K4PpFU2RnDOhL1o-Uc,1494
375
378
  plato/sims/agent_helpers.py,sha256=kITvQywoTCS8mGhro3jZWuPJHDlje-UZujhjoahqhd0,10291
376
- plato/sims/cli.py,sha256=ySG5TNh9L2E-bgP0Jv4sbewReaoPw5jDYFAQk_jubuw,46093
379
+ plato/sims/cli.py,sha256=VaPZ_jeCbbR-A_l0UR1dz6Ur7UbHGRSHwO6W_9sZfm4,52512
377
380
  plato/sims/generate_clients.py,sha256=nEe39v3UOcks-ggv5jomcwN33R5U9n8MDNCpHoZ2lDg,5958
378
- plato/sims/registry.py,sha256=_xtjcI4HHGBsJ4c0kzxK90U2B_h6FK-5FAoAwyWZokQ,8777
381
+ plato/sims/registry.py,sha256=9qVSFzX575sfxvqPqCBiTExRZNNsEYr5Jl9DyxbJF08,12015
379
382
  plato/v1/__init__.py,sha256=t1Ejb7YCFOVSKZL9hJ0UsmEE1mULDvO__f75dz1UueQ,197
380
383
  plato/v1/audit_ui.py,sha256=zYYufJKn7291uCNb_59ItmDTYsPr7YLshBFwcAwl1LQ,10990
381
384
  plato/v1/cli.py,sha256=iEt58vvW7ab9YH0CLcBHvf4653fk1gcEdij4HZc10YY,269
@@ -390,8 +393,8 @@ plato/v1/sync_sdk.py,sha256=ztAvqR5yW_ALj8g97K6U-jSQzwzVNVKWlGZ-tdMUP_M,25620
390
393
  plato/v1/cli/__init__.py,sha256=om4b7PxgsoI7rEwuQelmQkqPdhMVn53_5qEN8kvksYw,105
391
394
  plato/v1/cli/agent.py,sha256=GUPDx6iZlGlW3q8QC863Vdrpe5_f6PBtcNo5vYipaEI,43329
392
395
  plato/v1/cli/main.py,sha256=ktPtBvMwykR7AjXmTQ6bmZkHdzpAjhX5Fq66cDbGSzA,6844
393
- plato/v1/cli/pm.py,sha256=sIrh7qVyL-GOI8cgCUDFO2StXCxaKkCpGoN2waMqiyw,47579
394
- plato/v1/cli/sandbox.py,sha256=r4VrZxfGLwLdmZyylw07dQ70glvsyBg3j7S_qU6UrRs,87801
396
+ plato/v1/cli/pm.py,sha256=wYeOyvaZFb7omQTpdHbKK72nC2CbS0jaoTCwfyCAKtI,47720
397
+ plato/v1/cli/sandbox.py,sha256=Qult0F-YIrgWLl6wAFM6CE-pqhEDJPz2jzuSKtnVZtk,87871
395
398
  plato/v1/cli/ssh.py,sha256=pePHD0lFPwSkATZYSannpFtHfJWKImAdLyS2463aRRw,6287
396
399
  plato/v1/cli/utils.py,sha256=be-llK6T6NHnIQl_Kfs-8EPu9JhIuZ_k9tJ3Ts-AKt4,3887
397
400
  plato/v1/cli/world.py,sha256=f-65n70-V2EBcYs9hbYqCXVT8n2xm7opIgmB5Z6yi3Y,9580
@@ -458,12 +461,12 @@ plato/v2/utils/db_cleanup.py,sha256=lnI5lsMHNHpG85Y99MaE4Rzc3618piuzhvH-uXO1zIc,
458
461
  plato/v2/utils/models.py,sha256=PwehSSnIRG-tM3tWL1PzZEH77ZHhIAZ9R0UPs6YknbM,1441
459
462
  plato/v2/utils/proxy_tunnel.py,sha256=8ZTd0jCGSfIHMvSv1fgEyacuISWnGPHLPbDglWroTzY,10463
460
463
  plato/worlds/README.md,sha256=TgG4aidude0ouJSCfY81Ev45hsUxPkO85HUIiWNqkcc,5463
461
- plato/worlds/__init__.py,sha256=0ogDVw5GEk4OT7FSD0Z7SrafTn_TBdo8DOU_v6ncbd4,1478
462
- plato/worlds/base.py,sha256=vLAHkYpYg4kl7LgftQ0uC6xXhASVqREogn6msNWA6Hk,9650
464
+ plato/worlds/__init__.py,sha256=crzpXFh4XD8eS4pYFTEUf3XgUf0wapFPT4npAu8sWwk,2078
465
+ plato/worlds/base.py,sha256=McV2QAuHYztSMfG8EXQML1kEPbdeADLt8tgiYpH35n4,10751
463
466
  plato/worlds/build_hook.py,sha256=KSoW0kqa5b7NyZ7MYOw2qsZ_2FkWuz0M3Ru7AKOP7Qw,3486
464
- plato/worlds/config.py,sha256=-K1dnlRL5I-DNYEoc1I4cKIsTw53X_1QrRY2SWJvRiQ,6256
465
- plato/worlds/runner.py,sha256=r9B2BxBae8_dM7y5cJf9xhThp_I1Qvf_tlPq2rs8qC8,4013
466
- plato_sdk_v2-2.1.15.dist-info/METADATA,sha256=jHsbu_NePI0IW_9sfReVw3o2ifWJxaqW5g8tqr3VfFI,8509
467
- plato_sdk_v2-2.1.15.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
468
- plato_sdk_v2-2.1.15.dist-info/entry_points.txt,sha256=upGMbJCx6YWUTKrPoYvYUYfFCqYr75nHDwhA-45m6p8,136
469
- plato_sdk_v2-2.1.15.dist-info/RECORD,,
467
+ plato/worlds/config.py,sha256=potOy85jYReODN4ndhTp38ebblk2yKbWRrm9uXRi-Vw,9472
468
+ plato/worlds/runner.py,sha256=07fKyPYxem1vIKfPRo4le7eKWTkY3euDXugObVyAsf4,7858
469
+ plato_sdk_v2-2.1.17.dist-info/METADATA,sha256=ZTTHQEnqUbMipKnNNZWL86JfgLY6v67LYUifoemoBsQ,8509
470
+ plato_sdk_v2-2.1.17.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
471
+ plato_sdk_v2-2.1.17.dist-info/entry_points.txt,sha256=upGMbJCx6YWUTKrPoYvYUYfFCqYr75nHDwhA-45m6p8,136
472
+ plato_sdk_v2-2.1.17.dist-info/RECORD,,