plato-sdk-v2 2.3.0__py3-none-any.whl → 2.4.1__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/config.py CHANGED
@@ -72,6 +72,36 @@ class Env:
72
72
  self.required = required
73
73
 
74
74
 
75
+ class StateConfig(BaseModel):
76
+ """Configuration for world state persistence.
77
+
78
+ The state directory is a git-tracked directory that persists across checkpoints.
79
+ At each checkpoint, the state directory is git bundled and uploaded as an artifact.
80
+ On restore, bootstrap.sh downloads and unbundles the state before the world starts.
81
+
82
+ Attributes:
83
+ enabled: Whether to enable state persistence (default: True).
84
+ path: Path to the state directory (default: /state).
85
+ """
86
+
87
+ enabled: bool = True
88
+ path: str = "/state"
89
+
90
+
91
+ class CheckpointConfig(BaseModel):
92
+ """Configuration for automatic checkpointing during world execution.
93
+
94
+ Attributes:
95
+ enabled: Whether to enable automatic checkpoints after steps.
96
+ interval: Create checkpoint every N steps (default: 1 = every step).
97
+ exclude_envs: Environment aliases to exclude from checkpoints (default: ["runtime"]).
98
+ """
99
+
100
+ enabled: bool = True
101
+ interval: int = 1
102
+ exclude_envs: list[str] = Field(default_factory=lambda: ["runtime"])
103
+
104
+
75
105
  class RunConfig(BaseModel):
76
106
  """Base configuration for running a world.
77
107
 
@@ -96,18 +126,27 @@ class RunConfig(BaseModel):
96
126
 
97
127
  Attributes:
98
128
  session_id: Unique Chronos session identifier
99
- callback_url: Callback URL for status updates
129
+ otel_url: OTel endpoint URL (e.g., https://chronos.plato.so/api/otel)
130
+ upload_url: Presigned S3 URL for uploading artifacts (provided by Chronos)
100
131
  plato_session: Serialized Plato session for connecting to existing VM session
132
+ checkpoint: Configuration for automatic checkpoints after steps
101
133
  """
102
134
 
103
135
  session_id: str = ""
104
- callback_url: str = ""
136
+ otel_url: str = "" # OTel endpoint URL
137
+ upload_url: str = "" # Presigned S3 URL for uploads
105
138
  all_secrets: dict[str, str] = Field(default_factory=dict) # All secrets (world + agent)
106
139
 
107
140
  # Serialized Plato session for connecting to VM and sending heartbeats
108
141
  # This is the output of Session.dump() - used to restore session with Session.load()
109
142
  plato_session: SerializedSession | None = None
110
143
 
144
+ # Checkpoint configuration for automatic snapshots after steps
145
+ checkpoint: CheckpointConfig = Field(default_factory=CheckpointConfig)
146
+
147
+ # State persistence configuration
148
+ state: StateConfig = Field(default_factory=StateConfig)
149
+
111
150
  model_config = {"extra": "allow"}
112
151
 
113
152
  @classmethod
@@ -145,7 +184,7 @@ class RunConfig(BaseModel):
145
184
  envs = []
146
185
 
147
186
  # Skip runtime fields
148
- runtime_fields = {"session_id", "callback_url", "all_secrets", "plato_session"}
187
+ runtime_fields = {"session_id", "otel_url", "upload_url", "all_secrets", "plato_session", "checkpoint", "state"}
149
188
 
150
189
  for field_name, prop_schema in properties.items():
151
190
  if field_name in runtime_fields:
plato/worlds/runner.py CHANGED
@@ -3,16 +3,13 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
- import json
7
6
  import logging
8
- import os
9
- import platform
10
7
  from pathlib import Path
11
8
  from typing import Annotated
12
9
 
13
10
  import typer
14
11
 
15
- from plato.worlds.config import EnvConfig, RunConfig
12
+ from plato.worlds.config import RunConfig
16
13
 
17
14
  app = typer.Typer(
18
15
  name="plato-world-runner",
@@ -136,341 +133,6 @@ def list_worlds(
136
133
  typer.echo(f" {name} (v{version}): {desc}")
137
134
 
138
135
 
139
- async def _build_agent_image(
140
- agent_name: str,
141
- agents_dir: Path,
142
- plato_client_root: Path | None = None,
143
- ) -> bool:
144
- """Build a local agent Docker image.
145
-
146
- Args:
147
- agent_name: Name of the agent (e.g., "openhands")
148
- agents_dir: Directory containing agent subdirectories
149
- plato_client_root: Root of plato-client repo (for dev builds), or None for prod builds
150
-
151
- Returns:
152
- True if build succeeded, False otherwise
153
- """
154
- import subprocess
155
-
156
- # Resolve paths to absolute
157
- agents_dir = agents_dir.expanduser().resolve()
158
- agent_path = agents_dir / agent_name
159
- dockerfile_path = agent_path / "Dockerfile"
160
-
161
- if not dockerfile_path.exists():
162
- logger.warning(f"No Dockerfile found for agent '{agent_name}' at {dockerfile_path}")
163
- return False
164
-
165
- image_tag = f"{agent_name}:latest"
166
-
167
- # Determine build context and target
168
- if plato_client_root:
169
- plato_client_root = plato_client_root.expanduser().resolve()
170
-
171
- if plato_client_root and plato_client_root.exists():
172
- # Dev build from plato-client root (includes local python-sdk)
173
- build_context = str(plato_client_root)
174
- dockerfile_abs = str(dockerfile_path)
175
- target = "dev"
176
- logger.info(f"Building {image_tag} (dev mode from {build_context})...")
177
- else:
178
- # Prod build from agent directory
179
- build_context = str(agent_path)
180
- dockerfile_abs = str(dockerfile_path)
181
- target = "prod"
182
- logger.info(f"Building {image_tag} (prod mode from {build_context})...")
183
-
184
- cmd = [
185
- "docker",
186
- "build",
187
- "--target",
188
- target,
189
- "-t",
190
- image_tag,
191
- "-f",
192
- dockerfile_abs,
193
- ]
194
-
195
- # Use native platform for local dev on ARM Macs (avoids slow emulation)
196
- if platform.machine() == "arm64":
197
- cmd.extend(["--build-arg", "PLATFORM=linux/arm64"])
198
-
199
- cmd.append(build_context)
200
-
201
- logger.debug(f"Build command: {' '.join(cmd)}")
202
-
203
- result = subprocess.run(cmd, capture_output=True, text=True)
204
-
205
- if result.returncode != 0:
206
- logger.error(f"Failed to build {image_tag}:\n{result.stderr}")
207
- return False
208
-
209
- logger.info(f"Successfully built {image_tag}")
210
- return True
211
-
212
-
213
- def _extract_agent_images_from_config(config_data: dict) -> list[str]:
214
- """Extract agent image names from config data.
215
-
216
- Args:
217
- config_data: Raw config dictionary
218
-
219
- Returns:
220
- List of image names (without tags) that are local (not from a registry)
221
- """
222
- images = []
223
-
224
- # Check agents section
225
- agents = config_data.get("agents", {})
226
- for agent_config in agents.values():
227
- if isinstance(agent_config, dict):
228
- image = agent_config.get("image", "")
229
- # Only include local images (no registry prefix like ghcr.io/)
230
- if image and "/" not in image.split(":")[0]:
231
- # Extract name without tag
232
- name = image.split(":")[0]
233
- if name not in images:
234
- images.append(name)
235
-
236
- # Also check direct coder/verifier fields
237
- for field in ["coder", "verifier"]:
238
- agent_config = config_data.get(field, {})
239
- if isinstance(agent_config, dict):
240
- image = agent_config.get("image", "")
241
- if image and "/" not in image.split(":")[0]:
242
- name = image.split(":")[0]
243
- if name not in images:
244
- images.append(name)
245
-
246
- return images
247
-
248
-
249
- async def _run_dev(
250
- world_name: str,
251
- config_path: Path,
252
- env_timeout: int = 600,
253
- chronos_url: str | None = None,
254
- api_key: str | None = None,
255
- agents_dir: Path | None = None,
256
- ) -> None:
257
- """Run a world locally with automatic environment creation.
258
-
259
- This mimics what Chronos does but runs locally for debugging:
260
- 1. Load and parse the config
261
- 2. Build local agent images if --agents-dir is provided
262
- 3. Create Plato session with all environments
263
- 4. Optionally initialize Chronos logging for callbacks
264
- 5. Run the world with the session attached
265
-
266
- Args:
267
- world_name: Name of the world to run
268
- config_path: Path to the config JSON file
269
- env_timeout: Timeout for environment creation (seconds)
270
- chronos_url: Optional Chronos base URL for sending log events
271
- api_key: Optional Plato API key (used for Chronos session creation)
272
- agents_dir: Optional directory containing agent source code
273
- """
274
- from uuid import uuid4
275
-
276
- from plato.v2 import AsyncPlato
277
- from plato.worlds.base import get_world
278
-
279
- discover_worlds()
280
-
281
- world_cls = get_world(world_name)
282
- if world_cls is None:
283
- from plato.worlds.base import get_registered_worlds
284
-
285
- available = list(get_registered_worlds().keys())
286
- raise ValueError(f"World '{world_name}' not found. Available: {available}")
287
-
288
- # Load config
289
- config_class = world_cls.get_config_class()
290
- with open(config_path) as f:
291
- config_data = json.load(f)
292
-
293
- # Parse the config to get typed access
294
- run_config = config_class._from_dict(config_data.copy())
295
-
296
- # Build local agent images if agents_dir is provided
297
- if agents_dir:
298
- # Resolve agents_dir to absolute path
299
- agents_dir = agents_dir.expanduser().resolve()
300
- agent_images = _extract_agent_images_from_config(config_data)
301
- if agent_images:
302
- logger.info(f"Building local agent images: {agent_images}")
303
- # Determine if we're in a plato-client repo for dev builds
304
- # (agents_dir is something like /path/to/plato-client/agents)
305
- plato_client_root = agents_dir.parent if agents_dir.name == "agents" else None
306
- for agent_name in agent_images:
307
- success = await _build_agent_image(agent_name, agents_dir, plato_client_root)
308
- if not success:
309
- raise RuntimeError(f"Failed to build agent image: {agent_name}")
310
- else:
311
- logger.info("No local agent images found in config")
312
-
313
- # Get environment configs from the parsed config
314
- env_configs: list[EnvConfig] = run_config.get_envs()
315
-
316
- # Create Plato client
317
- plato = AsyncPlato()
318
- session = None
319
-
320
- # Initialize Chronos logging if URL provided
321
- chronos_session_id: str | None = None
322
- if chronos_url:
323
- from plato.agents import init_logging
324
-
325
- chronos_session_id = f"dev-{uuid4().hex[:8]}"
326
- callback_url = f"{chronos_url.rstrip('/')}/api/v1/callback"
327
- init_logging(
328
- callback_url=callback_url,
329
- session_id=chronos_session_id,
330
- )
331
- logger.info(f"Chronos logging enabled: {callback_url} (session: {chronos_session_id})")
332
-
333
- # Update run_config with session info for agents
334
- run_config.session_id = chronos_session_id
335
- run_config.callback_url = callback_url
336
-
337
- try:
338
- if env_configs:
339
- logger.info(f"Creating {len(env_configs)} environments...")
340
- session = await plato.sessions.create(envs=env_configs, timeout=env_timeout)
341
- logger.info(f"Created Plato session: {session.session_id}")
342
- logger.info(f"Environments: {[e.alias for e in session.envs]}")
343
-
344
- # Serialize and add to config
345
- serialized = session.dump()
346
- run_config.plato_session = serialized
347
- else:
348
- logger.info("No environments defined for this world")
349
-
350
- # Run the world
351
- logger.info(f"Starting world '{world_name}'...")
352
- world_instance = world_cls()
353
- await world_instance.run(run_config)
354
-
355
- finally:
356
- # Cleanup
357
- if session:
358
- logger.info("Closing Plato session...")
359
- await session.close()
360
- await plato.close()
361
-
362
- # Reset logging
363
- if chronos_url:
364
- from plato.agents import reset_logging
365
-
366
- reset_logging()
367
-
368
-
369
- def _setup_colored_logging(verbose: bool = False) -> None:
370
- """Setup colored logging with filtered noisy loggers."""
371
- log_level = logging.DEBUG if verbose else logging.INFO
372
-
373
- # Define colors for different log levels
374
- colors = {
375
- "DEBUG": "\033[36m", # Cyan
376
- "INFO": "\033[32m", # Green
377
- "WARNING": "\033[33m", # Yellow
378
- "ERROR": "\033[31m", # Red
379
- "CRITICAL": "\033[35m", # Magenta
380
- }
381
- reset = "\033[0m"
382
-
383
- class ColoredFormatter(logging.Formatter):
384
- def format(self, record: logging.LogRecord) -> str:
385
- color = colors.get(record.levelname, "")
386
- record.levelname = f"{color}{record.levelname}{reset}"
387
- record.name = f"\033[34m{record.name}{reset}" # Blue for logger name
388
- return super().format(record)
389
-
390
- # Create handler with colored formatter
391
- handler = logging.StreamHandler()
392
- handler.setFormatter(
393
- ColoredFormatter(
394
- "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
395
- datefmt="%H:%M:%S",
396
- )
397
- )
398
-
399
- # Configure root logger
400
- root_logger = logging.getLogger()
401
- root_logger.setLevel(log_level)
402
- root_logger.handlers = [handler]
403
-
404
- # Silence noisy HTTP loggers
405
- for noisy_logger in ["httpcore", "httpx", "urllib3", "hpack"]:
406
- logging.getLogger(noisy_logger).setLevel(logging.WARNING)
407
-
408
-
409
- @app.command("dev")
410
- def dev(
411
- world: Annotated[str, typer.Option("--world", "-w", help="World name to run")],
412
- config: Annotated[Path, typer.Option("--config", "-c", help="Path to config JSON file")],
413
- env_timeout: Annotated[int, typer.Option("--env-timeout", help="Timeout for environment creation (seconds)")] = 600,
414
- chronos_url: Annotated[
415
- str | None, typer.Option("--chronos-url", help="Chronos base URL for log events (e.g., http://localhost:8000)")
416
- ] = None,
417
- api_key: Annotated[str | None, typer.Option("--api-key", help="Plato API key for Chronos authentication")] = None,
418
- agents_dir: Annotated[
419
- Path | None,
420
- typer.Option("--agents-dir", "-a", help="Directory containing agent source code (builds local images)"),
421
- ] = None,
422
- verbose: Annotated[bool, typer.Option("--verbose", "-v", help="Enable verbose logging")] = False,
423
- ) -> None:
424
- """Run a world locally for development/debugging.
425
-
426
- This creates Plato environments automatically (like Chronos does)
427
- and runs the world with the session attached.
428
-
429
- Optionally sends log events to a Chronos server for real-time monitoring.
430
-
431
- Example config.json:
432
- {
433
- "instruction": "Create a git repo and upload files to S3",
434
- "coder": {
435
- "image": "openhands:latest",
436
- "config": {"model_name": "gemini/gemini-3-flash-preview"}
437
- },
438
- "secrets": {
439
- "gemini_api_key": "..."
440
- }
441
- }
442
-
443
- Environment variables:
444
- PLATO_API_KEY: API key for Plato (required)
445
-
446
- Examples:
447
- # Basic usage
448
- plato-world-runner dev -w code -c config.json
449
-
450
- # With local agent builds (from plato-client repo)
451
- plato-world-runner dev -w code -c config.json --agents-dir ~/plato-client/agents
452
-
453
- # With Chronos logging
454
- plato-world-runner dev -w code -c config.json --chronos-url http://localhost:8000
455
- """
456
- # Setup colored logging with filtered noisy loggers
457
- _setup_colored_logging(verbose)
458
-
459
- if not config.exists():
460
- typer.echo(f"Error: Config file not found: {config}", err=True)
461
- raise typer.Exit(1)
462
-
463
- if not os.environ.get("PLATO_API_KEY"):
464
- typer.echo("Error: PLATO_API_KEY environment variable required", err=True)
465
- raise typer.Exit(1)
466
-
467
- try:
468
- asyncio.run(_run_dev(world, config, env_timeout, chronos_url, api_key, agents_dir))
469
- except Exception as e:
470
- logger.exception(f"World execution failed: {e}")
471
- raise typer.Exit(1)
472
-
473
-
474
136
  def main() -> None:
475
137
  """CLI entry point."""
476
138
  app()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plato-sdk-v2
3
- Version: 2.3.0
3
+ Version: 2.4.1
4
4
  Summary: Python SDK for the Plato API
5
5
  Author-email: Plato <support@plato.so>
6
6
  License-Expression: MIT
@@ -21,6 +21,9 @@ Requires-Dist: google-genai>=1.0.0
21
21
  Requires-Dist: httpx>=0.25.0
22
22
  Requires-Dist: jinja2>=3.1.0
23
23
  Requires-Dist: openapi-pydantic>=0.5.1
24
+ Requires-Dist: opentelemetry-api>=1.20.0
25
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0
26
+ Requires-Dist: opentelemetry-sdk>=1.20.0
24
27
  Requires-Dist: pydantic-settings>=2.12.0
25
28
  Requires-Dist: pydantic>=2.0.0
26
29
  Requires-Dist: python-dotenv>=1.2.1
@@ -297,12 +297,13 @@ plato/_sims_generator/templates/python/errors.py.jinja,sha256=8L_FbHczBNLXJrbSlN
297
297
  plato/_sims_generator/templates/python/package_init.py.jinja,sha256=sOcJxUT0LuOWu5jOMGGKYxfCEjcYQv1hGF3n0iOA4hQ,986
298
298
  plato/_sims_generator/templates/python/tag_init.py.jinja,sha256=WB_9cv0JKIVg5TOXeSolET3tAfVg7sExjboh5jbCXz4,170
299
299
  plato/_sims_generator/templates/python/version_init.py.jinja,sha256=sGvFcYVfzXFyQDAe0PSOrg9yys93KE0XInFQNb1TvCY,179
300
- plato/agents/__init__.py,sha256=qslIFTVSe1yFeTRCKr8Z-mInWarj2HDbNZV4u6AiXek,2755
300
+ plato/agents/__init__.py,sha256=Cxc-HUMwRGQ4D1hHnFo9vt2AV5upPRYP4e3y8X6Hzr0,3052
301
+ plato/agents/artifacts.py,sha256=ljeI0wzsp7Q6uKqMb-k7kTb680Vizs54ohtM-d7zvOg,2929
301
302
  plato/agents/base.py,sha256=vUbPQuNSo6Ka2lIB_ZOXgi4EoAjtAD7GIj9LnNotam0,4577
302
303
  plato/agents/build.py,sha256=CNMbVQFs2_pYit1dA29Davve28Yi4c7TNK9wBB7odrE,1621
303
- plato/agents/config.py,sha256=VZVMdCmEQnoR0VkrGdScG8p6zSKVFe7BZPd2h8lKNjI,5460
304
- plato/agents/logging.py,sha256=z9rDlGPbrpcTS8PephbK2rDqT7thC1KyLkua4ypUkv4,12210
305
- plato/agents/runner.py,sha256=YoqG1QdNScIjSSH0vPgnm42LlqeAeVsFT01VL77ony0,5565
304
+ plato/agents/config.py,sha256=GWXEAbruNVI2q3XIWpQ9vGLK2wGhsFPYA-oekmAlrg8,5392
305
+ plato/agents/otel.py,sha256=A2LkkjBtjSe0eztr9UvYvSUOwfmShCgPg3OUN8nOyIo,9159
306
+ plato/agents/runner.py,sha256=piow_uO1eymreRMU-TX8tcIOn6aurafpjA5ptSR9JPM,9211
306
307
  plato/agents/trajectory.py,sha256=WdiBmua0KvCrNaM3qgPI7-7B4xmSkfbP4oZ_9_8qHzU,10529
307
308
  plato/chronos/__init__.py,sha256=RHMvSrQS_-vkKOyTRuAkp2gKDP1HEuBLDnw8jcZs1Jg,739
308
309
  plato/chronos/client.py,sha256=YcOGtHWERyOD9z8LKt8bRMVL0cEwL2hiAP4qQgdZlUI,5495
@@ -321,12 +322,6 @@ plato/chronos/api/auth/__init__.py,sha256=6qao3xT8yw9-WTpUlv4tVtpWhL2EycQd3I2WKQ
321
322
  plato/chronos/api/auth/debug_auth_api_auth_debug_get.py,sha256=L1RWyQ1w7V8dyhOAU2VQlT9x0jkeng3eIvZDOv9Gl2w,881
322
323
  plato/chronos/api/auth/get_auth_status_api_auth_status_get.py,sha256=i9JzH9vPeswvbWtBAkMikepbNAyNK8jpTcALU6ScG5s,1379
323
324
  plato/chronos/api/auth/get_current_user_route_api_auth_me_get.py,sha256=w9zz7ivQpYKvV6FPIEuNHfI5BOl9bu3FYbJ5ADEuTPc,1210
324
- plato/chronos/api/callback/__init__.py,sha256=KxC9frS5-0DzwOz4eympnoTvki7MslueKfRiZNdfSYg,264
325
- plato/chronos/api/callback/push_agent_logs.py,sha256=MWL9-2qzRXnrXdUQktCAaIKHAOo8z7vPdaMOqgrJ6vI,1611
326
- plato/chronos/api/callback/update_agent_status.py,sha256=I3N2T_670f030EvoNrX9koKQL78OjHoIRbUKaIXlktk,1323
327
- plato/chronos/api/callback/upload_artifacts.py,sha256=AUg4TxFSHG6hvvSR1HyOh18eOLNuW-mtjPxXVxrWPr4,1526
328
- plato/chronos/api/callback/upload_logs_zip.py,sha256=ZwB0zn23dMtfgXjkeraUG09b6OYZ2Nbfy_j0_LKndxY,1321
329
- plato/chronos/api/callback/upload_trajectory.py,sha256=-cEktjBjzfxyMipJrUFwzqW1BAiKVX3bJYEHk33D9CU,1421
330
325
  plato/chronos/api/default/__init__.py,sha256=TCF1Fl95ZyiR9-xHzf_R2A6TNb7k59N1VfSI5PAj4Pg,72
331
326
  plato/chronos/api/default/health.py,sha256=PvBLZXdYptL9d5_BEmzUsbUjQJTNGw5E4AFryPYiruw,781
332
327
  plato/chronos/api/jobs/__init__.py,sha256=JP76_irfuFV31HOgazh7Y81GSkcunJP_eYWX8Pqq1U0,80
@@ -372,7 +367,7 @@ plato/chronos/api/worlds/create_world.py,sha256=H6yl5QIazNXgryOR5rvscSIMf8Y9kjc6
372
367
  plato/chronos/api/worlds/delete_world.py,sha256=UETu3Zk0e2VkDdAyMilv1ev-0g_j-oujH1Dc8DBqQOc,1239
373
368
  plato/chronos/api/worlds/get_world.py,sha256=eHTM1U5JiNTaZwYLh7x4QVBoRQeI5kaJ9o6xSi4-nos,1356
374
369
  plato/chronos/api/worlds/list_worlds.py,sha256=hBAuGb69tlasyn-kV_LNr9x6Rr7SHhST5hXJn1uqMf8,1253
375
- plato/chronos/models/__init__.py,sha256=5Hil8v_jFX1YU6LpOfqyJM4WV867Ckv6CX052Q4SCso,20996
370
+ plato/chronos/models/__init__.py,sha256=t9Kn9qwMBm2S9qs9weF0-CBCg4o1-u_W_3kDFQb-aDU,21328
376
371
  plato/sims/README.md,sha256=FIbJhNVNAV-SO6dq_cXX3Rg0C7HdQCfEY9YxGlkCmsM,6902
377
372
  plato/sims/__init__.py,sha256=tnoCGKZwNx6h22tEWLujdpLv6K4PpFU2RnDOhL1o-Uc,1494
378
373
  plato/sims/agent_helpers.py,sha256=kITvQywoTCS8mGhro3jZWuPJHDlje-UZujhjoahqhd0,10291
@@ -392,14 +387,15 @@ plato/v1/sync_flow_executor.py,sha256=kgvNYOtA9FHeNfP7qb8ZPUIlTsfIss_Z98W8uX5vec
392
387
  plato/v1/sync_sdk.py,sha256=2sedg1QJiSxr1I3kCyfaLAnlAgHlbblc3QQP_47O30k,25697
393
388
  plato/v1/cli/__init__.py,sha256=om4b7PxgsoI7rEwuQelmQkqPdhMVn53_5qEN8kvksYw,105
394
389
  plato/v1/cli/agent.py,sha256=G6TV3blG_BqMDBWS-CG7GwzqoqcJTMsIKQ88jvLXb4k,43745
395
- plato/v1/cli/main.py,sha256=ZBF9J82Cp6TB-1mLkabJryxP44yNAYJoKE8K7LUNQng,6916
396
- plato/v1/cli/pm.py,sha256=uLM6WszKqxq9Czg1FraDyWb9_INUuHZq63imvRYfRLw,49734
397
- plato/v1/cli/sandbox.py,sha256=7VoiDIL6u2_8wZI4sj9J6CyI8IMfjHmHOp8FPiXs-3U,89411
398
- plato/v1/cli/sim.py,sha256=qF3H2RqMS96kQX8MwDpqXskZhpM4YFSgb283wcsMbfQ,266
399
- plato/v1/cli/ssh.py,sha256=pePHD0lFPwSkATZYSannpFtHfJWKImAdLyS2463aRRw,6287
400
- plato/v1/cli/utils.py,sha256=be-llK6T6NHnIQl_Kfs-8EPu9JhIuZ_k9tJ3Ts-AKt4,3887
401
- plato/v1/cli/verify.py,sha256=WZFxAqjpgq8vA0tc32g0VsNQjSZ1S0n4o_QoHQBkmsI,48404
390
+ plato/v1/cli/chronos.py,sha256=u0qJwZsV-me8P8GML2MzVO8KPhhN31KMIKoQL2gx9_8,26336
391
+ plato/v1/cli/main.py,sha256=iKUz6Mu-4-dgr29qOUmDqBaumOCzNQKZsHAalVtaH0Q,6932
392
+ plato/v1/cli/pm.py,sha256=TIvXBIWFDjr4s1girMMCuvHWQJkjpmsS-igAamddIWE,49746
393
+ plato/v1/cli/sandbox.py,sha256=jhTney-Pr8bGmWIXOjVIMtZJ7v7uIoRnuh3wfG7weRg,98718
394
+ plato/v1/cli/ssh.py,sha256=enrf7Y01ZeRIyHDEX0Yt7up5zEe7MCvE9u8SP4Oqiz4,6926
395
+ plato/v1/cli/utils.py,sha256=ba7Crv4OjDmgCv4SeB8UeZDin-iOdQw_3N6fd-g5XVk,4572
396
+ plato/v1/cli/verify.py,sha256=7QmQwfOOkr8a51f8xfVIr2zif7wGl2E8HOZTbOaIoV0,20671
402
397
  plato/v1/cli/world.py,sha256=yBUadOJs1QYm6Jmx_ACDzogybRq5x4B-BnTvGO_ulQk,9757
398
+ plato/v1/cli/templates/world-runner.Dockerfile,sha256=p59nPCAOUgphSiOpWA3eteRXUWTmZV6n57zn3dWUoYM,932
403
399
  plato/v1/examples/doordash_tasks.py,sha256=8Sz9qx-vTmiOAiCAbrDRvZGsA1qQQBr1KHbxXdjr7OI,23233
404
400
  plato/v1/examples/loadtest.py,sha256=ZsQYNN_fZjE7CbrbVJb4KDc0OLaH7b66iPrEHDhuw0U,5609
405
401
  plato/v1/examples/test_env.py,sha256=8kUISbZyMi0Xh9HK7Il1okKQyz0Iq-vAKWgzC8kqUfU,4513
@@ -462,13 +458,13 @@ plato/v2/utils/__init__.py,sha256=XLeFFsjXkm9g2raMmo7Wt4QN4hhCrNZDJKnpffJ4LtM,38
462
458
  plato/v2/utils/db_cleanup.py,sha256=lnI5lsMHNHpG85Y99MaE4Rzc3618piuzhvH-uXO1zIc,8702
463
459
  plato/v2/utils/models.py,sha256=PwehSSnIRG-tM3tWL1PzZEH77ZHhIAZ9R0UPs6YknbM,1441
464
460
  plato/v2/utils/proxy_tunnel.py,sha256=8ZTd0jCGSfIHMvSv1fgEyacuISWnGPHLPbDglWroTzY,10463
465
- plato/worlds/README.md,sha256=TgG4aidude0ouJSCfY81Ev45hsUxPkO85HUIiWNqkcc,5463
466
- plato/worlds/__init__.py,sha256=crzpXFh4XD8eS4pYFTEUf3XgUf0wapFPT4npAu8sWwk,2078
467
- plato/worlds/base.py,sha256=254kR0YmRaaOyenDC1jlRhNlEsENgUpcq-crkWJcRe8,15200
461
+ plato/worlds/README.md,sha256=XFOkEA3cNNcrWkk-Cxnsl-zn-y0kvUENKQRSqFKpdqw,5479
462
+ plato/worlds/__init__.py,sha256=ALoou3l5lXvs_YZc5eH6HdMHpvhnpzKWqz__aSC1jFc,2152
463
+ plato/worlds/base.py,sha256=1O3iKilXlr56mUPVovHY_BjM3S8T57FrotF4895qv5Y,30675
468
464
  plato/worlds/build_hook.py,sha256=KSoW0kqa5b7NyZ7MYOw2qsZ_2FkWuz0M3Ru7AKOP7Qw,3486
469
- plato/worlds/config.py,sha256=ggDcySspfeFry2KBUwhgnS6Po2KssYzwZNIDmVeGhPQ,9460
470
- plato/worlds/runner.py,sha256=RNnWFQ7rfEWE7TQ_tqgLHgLm1a4VxtP0mR7beALx4f0,15781
471
- plato_sdk_v2-2.3.0.dist-info/METADATA,sha256=JLEH19QIZ3S2O0k4btX1m3KZwYAcAlQm8tmsHFUeT7k,8508
472
- plato_sdk_v2-2.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
473
- plato_sdk_v2-2.3.0.dist-info/entry_points.txt,sha256=upGMbJCx6YWUTKrPoYvYUYfFCqYr75nHDwhA-45m6p8,136
474
- plato_sdk_v2-2.3.0.dist-info/RECORD,,
465
+ plato/worlds/config.py,sha256=a5frj3mt06rSlT25kE-L8Q2b2MTWkR-8cUoBKpC8tG4,11036
466
+ plato/worlds/runner.py,sha256=r9B2BxBae8_dM7y5cJf9xhThp_I1Qvf_tlPq2rs8qC8,4013
467
+ plato_sdk_v2-2.4.1.dist-info/METADATA,sha256=OH0RaQpDqg8_mtZ98cw5FuYZDWEuS68fzYqYs1K1W8s,8652
468
+ plato_sdk_v2-2.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
469
+ plato_sdk_v2-2.4.1.dist-info/entry_points.txt,sha256=upGMbJCx6YWUTKrPoYvYUYfFCqYr75nHDwhA-45m6p8,136
470
+ plato_sdk_v2-2.4.1.dist-info/RECORD,,