plato-sdk-v2 2.3.3__py3-none-any.whl → 2.4.2__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/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,393 +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 _create_chronos_session(
250
- chronos_url: str,
251
- api_key: str,
252
- world_name: str,
253
- world_config: dict,
254
- plato_session_id: str | None = None,
255
- ) -> tuple[str, str]:
256
- """Create a session in Chronos.
257
-
258
- Args:
259
- chronos_url: Chronos base URL (e.g., https://chronos.plato.so)
260
- api_key: Plato API key for authentication
261
- world_name: Name of the world being run
262
- world_config: World configuration dict
263
- plato_session_id: Optional Plato session ID if already created
264
-
265
- Returns:
266
- Tuple of (session_id, callback_url)
267
- """
268
- import httpx
269
-
270
- url = f"{chronos_url.rstrip('/')}/api/sessions"
271
-
272
- async with httpx.AsyncClient(timeout=30.0) as client:
273
- response = await client.post(
274
- url,
275
- json={
276
- "world_name": world_name,
277
- "world_config": world_config,
278
- "plato_session_id": plato_session_id,
279
- },
280
- headers={"x-api-key": api_key},
281
- )
282
- response.raise_for_status()
283
- data = response.json()
284
-
285
- return data["public_id"], data["callback_url"]
286
-
287
-
288
- async def _run_dev(
289
- world_name: str,
290
- config_path: Path,
291
- env_timeout: int = 7200,
292
- agents_dir: Path | None = None,
293
- ) -> None:
294
- """Run a world locally with automatic environment creation.
295
-
296
- This mimics what Chronos does but runs locally for debugging:
297
- 1. Load and parse the config
298
- 2. Build local agent images if --agents-dir is provided
299
- 3. Create Plato session with all environments
300
- 4. Create Chronos session for logging/callbacks
301
- 5. Run the world with the session attached
302
-
303
- Requires environment variables:
304
- CHRONOS_URL: Chronos base URL (e.g., https://chronos.plato.so)
305
- PLATO_API_KEY: API key for Plato and Chronos authentication
306
-
307
- Args:
308
- world_name: Name of the world to run
309
- config_path: Path to the config JSON file
310
- env_timeout: Timeout for environment creation (seconds)
311
- agents_dir: Optional directory containing agent source code
312
- """
313
- from plato.v2 import AsyncPlato
314
- from plato.worlds.base import get_world
315
-
316
- # Get required env vars
317
- chronos_url = os.environ.get("CHRONOS_URL")
318
- api_key = os.environ.get("PLATO_API_KEY")
319
-
320
- if not chronos_url:
321
- raise ValueError("CHRONOS_URL environment variable is required")
322
- if not api_key:
323
- raise ValueError("PLATO_API_KEY environment variable is required")
324
-
325
- discover_worlds()
326
-
327
- world_cls = get_world(world_name)
328
- if world_cls is None:
329
- from plato.worlds.base import get_registered_worlds
330
-
331
- available = list(get_registered_worlds().keys())
332
- raise ValueError(f"World '{world_name}' not found. Available: {available}")
333
-
334
- # Load config
335
- config_class = world_cls.get_config_class()
336
- with open(config_path) as f:
337
- config_data = json.load(f)
338
-
339
- # Parse the config to get typed access
340
- run_config = config_class._from_dict(config_data.copy())
341
-
342
- # Build local agent images if agents_dir is provided
343
- if agents_dir:
344
- # Resolve agents_dir to absolute path
345
- agents_dir = agents_dir.expanduser().resolve()
346
- agent_images = _extract_agent_images_from_config(config_data)
347
- if agent_images:
348
- logger.info(f"Building local agent images: {agent_images}")
349
- # Determine if we're in a plato-client repo for dev builds
350
- # (agents_dir is something like /path/to/plato-client/agents)
351
- plato_client_root = agents_dir.parent if agents_dir.name == "agents" else None
352
- for agent_name in agent_images:
353
- success = await _build_agent_image(agent_name, agents_dir, plato_client_root)
354
- if not success:
355
- raise RuntimeError(f"Failed to build agent image: {agent_name}")
356
- else:
357
- logger.info("No local agent images found in config")
358
-
359
- # Get environment configs from the parsed config
360
- env_configs: list[EnvConfig] = run_config.get_envs()
361
-
362
- # Create Plato client
363
- plato = AsyncPlato()
364
- session = None
365
- plato_session_id: str | None = None
366
-
367
- try:
368
- if env_configs:
369
- logger.info(f"Creating {len(env_configs)} environments...")
370
- session = await plato.sessions.create(envs=env_configs, timeout=env_timeout)
371
- plato_session_id = session.session_id
372
- logger.info(f"Created Plato session: {plato_session_id}")
373
- logger.info(f"Environments: {[e.alias for e in session.envs]}")
374
-
375
- # Serialize and add to config
376
- serialized = session.dump()
377
- run_config.plato_session = serialized
378
- else:
379
- logger.info("No environments defined for this world")
380
-
381
- # Create Chronos session (after Plato session so we can link them)
382
- logger.info(f"Creating Chronos session at {chronos_url}...")
383
- chronos_session_id, callback_url = await _create_chronos_session(
384
- chronos_url=chronos_url,
385
- api_key=api_key,
386
- world_name=world_name,
387
- world_config=config_data,
388
- plato_session_id=plato_session_id,
389
- )
390
- logger.info(f"Created Chronos session: {chronos_session_id}")
391
- logger.info(f"View at: {chronos_url}/sessions/{chronos_session_id}")
392
-
393
- # Initialize logging
394
- from plato.agents import init_logging
395
-
396
- init_logging(
397
- callback_url=callback_url,
398
- session_id=chronos_session_id,
399
- )
400
-
401
- # Update run_config with session info for agents
402
- run_config.session_id = chronos_session_id
403
- run_config.callback_url = callback_url
404
-
405
- # Run the world
406
- logger.info(f"Starting world '{world_name}'...")
407
- world_instance = world_cls()
408
- await world_instance.run(run_config)
409
-
410
- finally:
411
- # Cleanup
412
- if session:
413
- logger.info("Closing Plato session...")
414
- await session.close()
415
- await plato.close()
416
-
417
- # Reset logging
418
- from plato.agents import reset_logging
419
-
420
- reset_logging()
421
-
422
-
423
- def _setup_colored_logging(verbose: bool = False) -> None:
424
- """Setup colored logging with filtered noisy loggers."""
425
- log_level = logging.DEBUG if verbose else logging.INFO
426
-
427
- # Define colors for different log levels
428
- colors = {
429
- "DEBUG": "\033[36m", # Cyan
430
- "INFO": "\033[32m", # Green
431
- "WARNING": "\033[33m", # Yellow
432
- "ERROR": "\033[31m", # Red
433
- "CRITICAL": "\033[35m", # Magenta
434
- }
435
- reset = "\033[0m"
436
-
437
- class ColoredFormatter(logging.Formatter):
438
- def format(self, record: logging.LogRecord) -> str:
439
- color = colors.get(record.levelname, "")
440
- record.levelname = f"{color}{record.levelname}{reset}"
441
- record.name = f"\033[34m{record.name}{reset}" # Blue for logger name
442
- return super().format(record)
443
-
444
- # Create handler with colored formatter
445
- handler = logging.StreamHandler()
446
- handler.setFormatter(
447
- ColoredFormatter(
448
- "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
449
- datefmt="%H:%M:%S",
450
- )
451
- )
452
-
453
- # Configure root logger
454
- root_logger = logging.getLogger()
455
- root_logger.setLevel(log_level)
456
- root_logger.handlers = [handler]
457
-
458
- # Silence noisy HTTP loggers
459
- for noisy_logger in ["httpcore", "httpx", "urllib3", "hpack"]:
460
- logging.getLogger(noisy_logger).setLevel(logging.WARNING)
461
-
462
-
463
- @app.command("dev")
464
- def dev(
465
- world: Annotated[str, typer.Option("--world", "-w", help="World name to run")],
466
- config: Annotated[Path, typer.Option("--config", "-c", help="Path to config JSON file")],
467
- env_timeout: Annotated[
468
- int, typer.Option("--env-timeout", help="Timeout for environment creation (seconds)")
469
- ] = 7200,
470
- agents_dir: Annotated[
471
- Path | None,
472
- typer.Option("--agents-dir", "-a", help="Directory containing agent source code (builds local images)"),
473
- ] = None,
474
- verbose: Annotated[bool, typer.Option("--verbose", "-v", help="Enable verbose logging")] = False,
475
- ) -> None:
476
- """Run a world locally for development/debugging.
477
-
478
- This creates Plato environments automatically (like Chronos does),
479
- creates a Chronos session for logging, and runs the world.
480
-
481
- Example config.json:
482
- {
483
- "instruction": "Create a git repo and upload files to S3",
484
- "coder": {
485
- "image": "openhands:latest",
486
- "config": {"model_name": "gemini/gemini-3-flash-preview"}
487
- },
488
- "secrets": {
489
- "gemini_api_key": "..."
490
- }
491
- }
492
-
493
- Required environment variables:
494
- CHRONOS_URL: Chronos base URL (e.g., https://chronos.plato.so)
495
- PLATO_API_KEY: API key for Plato and Chronos authentication
496
-
497
- Examples:
498
- # Basic usage
499
- CHRONOS_URL=https://chronos.plato.so plato-world-runner dev -w code -c config.json
500
-
501
- # With local agent builds (from plato-client repo)
502
- plato-world-runner dev -w code -c config.json --agents-dir ~/plato-client/agents
503
- """
504
- # Setup colored logging with filtered noisy loggers
505
- _setup_colored_logging(verbose)
506
-
507
- if not config.exists():
508
- typer.echo(f"Error: Config file not found: {config}", err=True)
509
- raise typer.Exit(1)
510
-
511
- if not os.environ.get("CHRONOS_URL"):
512
- typer.echo("Error: CHRONOS_URL environment variable required", err=True)
513
- raise typer.Exit(1)
514
-
515
- if not os.environ.get("PLATO_API_KEY"):
516
- typer.echo("Error: PLATO_API_KEY environment variable required", err=True)
517
- raise typer.Exit(1)
518
-
519
- try:
520
- asyncio.run(_run_dev(world, config, env_timeout, agents_dir))
521
- except Exception as e:
522
- logger.exception(f"World execution failed: {e}")
523
- raise typer.Exit(1)
524
-
525
-
526
136
  def main() -> None:
527
137
  """CLI entry point."""
528
138
  app()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plato-sdk-v2
3
- Version: 2.3.3
3
+ Version: 2.4.2
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
@@ -44,8 +47,6 @@ Description-Content-Type: text/markdown
44
47
 
45
48
  # Plato Python SDK
46
49
 
47
-
48
-
49
50
  Python SDK for the Plato platform. Uses [Harbor](https://harborframework.com) for agent execution.
50
51
 
51
52
  ## Installation
@@ -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=1l-Vw5SFydmPsl1toXdc2oH3eLhFwz6jtI_DKUx4vmo,2847
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=bL3Q14YeFxWCQydGKrQzQPgKQzBoCCXy_AAQPZpBylU,16307
305
- plato/agents/runner.py,sha256=UQWg3gpYhWLnGLB6Bs595qH7nZV-ch-u5fPlkltT_kc,6812
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
@@ -391,14 +386,16 @@ plato/v1/sync_env.py,sha256=UIfDpx3nPHBNWzahSddvol0SvfK9vU4mr3MOIOPCGr8,24878
391
386
  plato/v1/sync_flow_executor.py,sha256=kgvNYOtA9FHeNfP7qb8ZPUIlTsfIss_Z98W8uX5veck,19233
392
387
  plato/v1/sync_sdk.py,sha256=2sedg1QJiSxr1I3kCyfaLAnlAgHlbblc3QQP_47O30k,25697
393
388
  plato/v1/cli/__init__.py,sha256=om4b7PxgsoI7rEwuQelmQkqPdhMVn53_5qEN8kvksYw,105
394
- plato/v1/cli/agent.py,sha256=G6TV3blG_BqMDBWS-CG7GwzqoqcJTMsIKQ88jvLXb4k,43745
395
- plato/v1/cli/main.py,sha256=ktPtBvMwykR7AjXmTQ6bmZkHdzpAjhX5Fq66cDbGSzA,6844
396
- plato/v1/cli/pm.py,sha256=uLM6WszKqxq9Czg1FraDyWb9_INUuHZq63imvRYfRLw,49734
397
- plato/v1/cli/sandbox.py,sha256=5rth_jL73L72GC0VJ0meXRgZo2EpsJ_qI3ipFjfXzJY,95185
398
- plato/v1/cli/ssh.py,sha256=10ag6S1sxMcAmvcg24qy-yYwXb1miWfqxkXOs4QX8u0,6623
399
- plato/v1/cli/utils.py,sha256=be-llK6T6NHnIQl_Kfs-8EPu9JhIuZ_k9tJ3Ts-AKt4,3887
389
+ plato/v1/cli/agent.py,sha256=EbmEKWCMC5DJjmVDrYuwGenhIDgPjie8hdwrDOTSXaY,43766
390
+ plato/v1/cli/chronos.py,sha256=VLsvh34R7dusV5BckYTZAIsCBihQkO5cxZDBq8S2x3I,25532
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
400
396
  plato/v1/cli/verify.py,sha256=7QmQwfOOkr8a51f8xfVIr2zif7wGl2E8HOZTbOaIoV0,20671
401
397
  plato/v1/cli/world.py,sha256=yBUadOJs1QYm6Jmx_ACDzogybRq5x4B-BnTvGO_ulQk,9757
398
+ plato/v1/cli/templates/world-runner.Dockerfile,sha256=p59nPCAOUgphSiOpWA3eteRXUWTmZV6n57zn3dWUoYM,932
402
399
  plato/v1/examples/doordash_tasks.py,sha256=8Sz9qx-vTmiOAiCAbrDRvZGsA1qQQBr1KHbxXdjr7OI,23233
403
400
  plato/v1/examples/loadtest.py,sha256=ZsQYNN_fZjE7CbrbVJb4KDc0OLaH7b66iPrEHDhuw0U,5609
404
401
  plato/v1/examples/test_env.py,sha256=8kUISbZyMi0Xh9HK7Il1okKQyz0Iq-vAKWgzC8kqUfU,4513
@@ -461,13 +458,13 @@ plato/v2/utils/__init__.py,sha256=XLeFFsjXkm9g2raMmo7Wt4QN4hhCrNZDJKnpffJ4LtM,38
461
458
  plato/v2/utils/db_cleanup.py,sha256=lnI5lsMHNHpG85Y99MaE4Rzc3618piuzhvH-uXO1zIc,8702
462
459
  plato/v2/utils/models.py,sha256=PwehSSnIRG-tM3tWL1PzZEH77ZHhIAZ9R0UPs6YknbM,1441
463
460
  plato/v2/utils/proxy_tunnel.py,sha256=8ZTd0jCGSfIHMvSv1fgEyacuISWnGPHLPbDglWroTzY,10463
464
- plato/worlds/README.md,sha256=TgG4aidude0ouJSCfY81Ev45hsUxPkO85HUIiWNqkcc,5463
461
+ plato/worlds/README.md,sha256=XFOkEA3cNNcrWkk-Cxnsl-zn-y0kvUENKQRSqFKpdqw,5479
465
462
  plato/worlds/__init__.py,sha256=ALoou3l5lXvs_YZc5eH6HdMHpvhnpzKWqz__aSC1jFc,2152
466
- plato/worlds/base.py,sha256=KsDq1TVVd4BKEFo42WodF4DPgodr00Gd1NrfzZEPqyw,25632
463
+ plato/worlds/base.py,sha256=1O3iKilXlr56mUPVovHY_BjM3S8T57FrotF4895qv5Y,30675
467
464
  plato/worlds/build_hook.py,sha256=KSoW0kqa5b7NyZ7MYOw2qsZ_2FkWuz0M3Ru7AKOP7Qw,3486
468
- plato/worlds/config.py,sha256=fkWoetCawIPf5xgj5EyJCvopmPPzZQAqt0Ke9P4hq5c,10845
469
- plato/worlds/runner.py,sha256=qC7eIZScXgIb9xeuLkhpSQqgNjDkzmEPgqJFRkrEJD4,17271
470
- plato_sdk_v2-2.3.3.dist-info/METADATA,sha256=U8DgV6t7AD7KedZtHsvH1tI86y6oGr9hKd7VYNjUvKM,8510
471
- plato_sdk_v2-2.3.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
472
- plato_sdk_v2-2.3.3.dist-info/entry_points.txt,sha256=upGMbJCx6YWUTKrPoYvYUYfFCqYr75nHDwhA-45m6p8,136
473
- plato_sdk_v2-2.3.3.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.2.dist-info/METADATA,sha256=1D5uBnPNi-3B2f5qSsi7WVQ0ezOEBNik0xHr5b0-YFc,8652
468
+ plato_sdk_v2-2.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
469
+ plato_sdk_v2-2.4.2.dist-info/entry_points.txt,sha256=upGMbJCx6YWUTKrPoYvYUYfFCqYr75nHDwhA-45m6p8,136
470
+ plato_sdk_v2-2.4.2.dist-info/RECORD,,