plato-sdk-v2 2.8.7__py3-none-any.whl → 2.8.8__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.
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
- # filename: tmp97yexy9o.json
3
- # timestamp: 2026-02-02T07:59:03+00:00
2
+ # filename: tmpu23ownyz.json
3
+ # timestamp: 2026-02-02T20:25:20+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1206,6 +1206,11 @@ class RootfsStorageBackend(Enum):
1206
1206
  blockdiff_disk = "blockdiff_disk"
1207
1207
 
1208
1208
 
1209
+ class RootfsStorageBackend1(Enum):
1210
+ snapshot_store = "snapshot-store"
1211
+ snapshot_store_disk = "snapshot-store-disk"
1212
+
1213
+
1209
1214
  class EnvFromSimulator(BaseModel):
1210
1215
  model_config = ConfigDict(
1211
1216
  extra="allow",
@@ -1218,9 +1223,13 @@ class EnvFromSimulator(BaseModel):
1218
1223
  """
1219
1224
  Simulator/service name
1220
1225
  """
1221
- tag: Annotated[str | None, Field(title="Tag")] = "latest"
1226
+ tag: Annotated[str | None, Field(title="Tag")] = None
1227
+ """
1228
+ Artifact tag. If neither tag nor version provided, defaults to 'latest'.
1229
+ """
1230
+ version: Annotated[str | None, Field(title="Version")] = None
1222
1231
  """
1223
- Artifact tag (defaults to 'latest')
1232
+ Artifact version (git_hash). If provided, looks up by version instead of tag.
1224
1233
  """
1225
1234
  dataset: Annotated[str | None, Field(title="Dataset")] = None
1226
1235
  """
@@ -1872,7 +1881,7 @@ class NodeBuildConfig(BaseModel):
1872
1881
  SSH public key for VM access. Derived from private key if not set.
1873
1882
  """
1874
1883
  default_image: Annotated[str | None, Field(title="Default Image")] = (
1875
- "383806609161.dkr.ecr.us-west-1.amazonaws.com/vm/rootfs/plato-ubuntu-22.04:1.1.0"
1884
+ "383806609161.dkr.ecr.us-west-1.amazonaws.com/vm/rootfs/plato-ubuntu-22.04:2.0.0"
1876
1885
  )
1877
1886
  """
1878
1887
  Default VM image URL with tag (e.g., 'ecr-url/repo:tag').
@@ -2099,9 +2108,9 @@ class NodeSnapshotStoreConfig(BaseModel):
2099
2108
  """
2100
2109
  Postgres DSN for snapshot-store metadata.
2101
2110
  """
2102
- cache_mb: Annotated[int | None, Field(title="Cache Mb")] = 0
2111
+ cache_mb: Annotated[int | None, Field(title="Cache Mb")] = 10240
2103
2112
  """
2104
- Snapshot-store userspace decompressed page cache size in MB (0 to disable). This cache deduplicates pages by content hash across all manifests. For memory mounts (mount-mem): direct_io is disabled by default, so the kernel page cache already handles caching and deduplication for mmap'd files. Multiple VMs restoring from the same snapshot share kernel-cached pages automatically. The userspace cache is redundant here. For disk mounts (mount-tree): direct_io is enabled by default for overlay write coherency, bypassing the kernel cache. However, the userspace cache only helps for unmodified base image pages read by multiple VMs. Since disk workloads involve frequent writes (logs, temp files, databases), written pages are served from the overlay and bypass this cache entirely. The benefit is marginal for typical workloads. Recommendation: Leave at 0 for most deployments.
2113
+ Snapshot-store userspace decompressed page cache size in MB (0 to disable). This cache deduplicates pages by content hash across all manifests. For memory mounts (mount-mem): direct_io is disabled by default, so the kernel page cache already handles caching and deduplication for mmap'd files. Multiple VMs restoring from the same snapshot share kernel-cached pages automatically. The userspace cache is less beneficial here but can still help. For disk mounts (mount-tree): direct_io is enabled by default for overlay write coherency, bypassing the kernel cache. The userspace cache is important here for read-heavy workloads (Docker builds, package installs, etc.) that read many base image pages. Without caching, every read goes through FUSE decompression. Recommendation: 512MB for most deployments, increase for heavy disk I/O workloads.
2105
2114
  """
2106
2115
  compression_workers: Annotated[int | None, Field(title="Compression Workers")] = 1
2107
2116
  """
@@ -4617,7 +4626,10 @@ class EnvFromResource(BaseModel):
4617
4626
  """
4618
4627
  Custom Docker image URL (ECR). If not set, uses default from settings.
4619
4628
  """
4620
- rootfs_storage_backend: Annotated[RootfsStorageBackend | str | None, Field(title="Rootfs Storage Backend")] = None
4629
+ rootfs_storage_backend: Annotated[
4630
+ RootfsStorageBackend | RootfsStorageBackend1 | str | None,
4631
+ Field(title="Rootfs Storage Backend"),
4632
+ ] = None
4621
4633
  """
4622
4634
  Storage backend for rootfs ('sparse-s3' or 'snapshot-store'). If not set, uses default.
4623
4635
  """
plato/cli/chronos.py CHANGED
@@ -202,7 +202,7 @@ def example(
202
202
 
203
203
  def _get_world_runner_dockerfile() -> Path:
204
204
  """Get the path to the world runner Dockerfile template."""
205
- return Path(__file__).parent / "templates" / "world-runner.Dockerfile"
205
+ return Path(__file__).parent.parent / "v1" / "cli" / "templates" / "world-runner.Dockerfile"
206
206
 
207
207
 
208
208
  def _build_world_runner_image(platform_override: str | None = None) -> str:
@@ -338,8 +338,22 @@ def _build_agent_image(
338
338
  return True
339
339
 
340
340
 
341
- def _extract_agent_images_from_config(config_data: dict) -> list[str]:
342
- """Extract local agent image names from config data."""
341
+ def _extract_agent_name_from_image(image: str) -> str:
342
+ """Extract agent name from image reference (local or full registry path)."""
343
+ # Remove tag if present (e.g., "explorer:1.0.6" -> "explorer")
344
+ image_without_tag = image.split(":")[0]
345
+ # Get the last path component (e.g., "383806609161.dkr.ecr.../agents/plato/explorer" -> "explorer")
346
+ return image_without_tag.split("/")[-1]
347
+
348
+
349
+ def _extract_agent_images_from_config(config_data: dict, extract_all: bool = False) -> list[str]:
350
+ """Extract agent image names from config data.
351
+
352
+ Args:
353
+ config_data: The world configuration data
354
+ extract_all: If True, extract agent names from ALL images (including registry paths).
355
+ If False, only extract from local images (no registry prefix).
356
+ """
343
357
  images = []
344
358
 
345
359
  # Check agents section
@@ -347,9 +361,14 @@ def _extract_agent_images_from_config(config_data: dict) -> list[str]:
347
361
  for agent_config in agents.values():
348
362
  if isinstance(agent_config, dict):
349
363
  image = agent_config.get("image", "")
350
- # Only include local images (no registry prefix)
351
- if image and "/" not in image.split(":")[0]:
352
- name = image.split(":")[0]
364
+ if image:
365
+ if extract_all:
366
+ name = _extract_agent_name_from_image(image)
367
+ elif "/" not in image.split(":")[0]:
368
+ # Only include local images (no registry prefix)
369
+ name = image.split(":")[0]
370
+ else:
371
+ continue
353
372
  if name not in images:
354
373
  images.append(name)
355
374
 
@@ -358,14 +377,44 @@ def _extract_agent_images_from_config(config_data: dict) -> list[str]:
358
377
  agent_config = config_data.get(field, {})
359
378
  if isinstance(agent_config, dict):
360
379
  image = agent_config.get("image", "")
361
- if image and "/" not in image.split(":")[0]:
362
- name = image.split(":")[0]
380
+ if image:
381
+ if extract_all:
382
+ name = _extract_agent_name_from_image(image)
383
+ elif "/" not in image.split(":")[0]:
384
+ name = image.split(":")[0]
385
+ else:
386
+ continue
363
387
  if name not in images:
364
388
  images.append(name)
365
389
 
366
390
  return images
367
391
 
368
392
 
393
+ def _update_config_with_local_images(config_data: dict, built_agents: list[str]) -> dict:
394
+ """Update config to use local image tags for built agents."""
395
+ config_data = config_data.copy()
396
+
397
+ # Update agents section
398
+ if "agents" in config_data:
399
+ config_data["agents"] = config_data["agents"].copy()
400
+ for agent_name, agent_config in config_data["agents"].items():
401
+ if isinstance(agent_config, dict) and "image" in agent_config:
402
+ image_agent_name = _extract_agent_name_from_image(agent_config["image"])
403
+ if image_agent_name in built_agents:
404
+ config_data["agents"][agent_name] = agent_config.copy()
405
+ config_data["agents"][agent_name]["image"] = f"{image_agent_name}:latest"
406
+
407
+ # Update direct fields
408
+ for field in ["coder", "verifier", "skill_runner"]:
409
+ if field in config_data and isinstance(config_data[field], dict) and "image" in config_data[field]:
410
+ image_agent_name = _extract_agent_name_from_image(config_data[field]["image"])
411
+ if image_agent_name in built_agents:
412
+ config_data[field] = config_data[field].copy()
413
+ config_data[field]["image"] = f"{image_agent_name}:latest"
414
+
415
+ return config_data
416
+
417
+
369
418
  async def _create_chronos_session(
370
419
  chronos_url: str,
371
420
  api_key: str,
@@ -493,15 +542,29 @@ async def _run_dev_impl(
493
542
  world_name = world_package_name or "unknown"
494
543
 
495
544
  # Build local agent images if agents_dir is provided
545
+ built_agents: list[str] = []
496
546
  if agents_dir:
497
547
  agents_dir = agents_dir.expanduser().resolve()
498
- agent_images = _extract_agent_images_from_config(config_data)
548
+ # Extract all agent names (including from full registry paths) when agents_dir is provided
549
+ agent_images = _extract_agent_images_from_config(config_data, extract_all=True)
499
550
  if agent_images:
500
- console.print(f"[blue]Building agent images: {agent_images}[/blue]")
551
+ console.print(f"[blue]Checking for local agent builds: {agent_images}[/blue]")
501
552
  for agent_name in agent_images:
502
- success = _build_agent_image(agent_name, agents_dir, platform_override)
503
- if not success:
504
- raise RuntimeError(f"Failed to build agent image: {agent_name}")
553
+ # Check if agent exists locally
554
+ agent_path = agents_dir / agent_name
555
+ if agent_path.exists() and (agent_path / "Dockerfile").exists():
556
+ console.print(f"[blue]Building local agent: {agent_name}[/blue]")
557
+ success = _build_agent_image(agent_name, agents_dir, platform_override)
558
+ if not success:
559
+ raise RuntimeError(f"Failed to build agent image: {agent_name}")
560
+ built_agents.append(agent_name)
561
+ else:
562
+ console.print(f"[dim]No local agent found for '{agent_name}', using remote image[/dim]")
563
+
564
+ # Update config to use local images for built agents
565
+ if built_agents:
566
+ config_data = _update_config_with_local_images(config_data, built_agents)
567
+ console.print(f"[green]✅ Using local builds for: {built_agents}[/green]")
505
568
 
506
569
  # Import world module to get config class for environment detection
507
570
  # We need to dynamically load the world from world_dir