plato-sdk-v2 2.8.6__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.
- plato/_generated/models/__init__.py +20 -8
- plato/cli/chronos.py +76 -13
- plato/cli/compose.py +1379 -0
- plato/cli/main.py +4 -0
- plato/cli/pm.py +2 -1
- plato/cli/sandbox.py +62 -14
- plato/cli/session.py +492 -0
- plato/v2/async_/environment.py +572 -0
- plato/v2/async_/session.py +45 -0
- plato/v2/sync/environment.py +6 -0
- plato/v2/sync/sandbox.py +235 -37
- plato/v2/sync/session.py +9 -0
- plato/v2/types.py +46 -15
- {plato_sdk_v2-2.8.6.dist-info → plato_sdk_v2-2.8.8.dist-info}/METADATA +1 -1
- {plato_sdk_v2-2.8.6.dist-info → plato_sdk_v2-2.8.8.dist-info}/RECORD +17 -15
- {plato_sdk_v2-2.8.6.dist-info → plato_sdk_v2-2.8.8.dist-info}/WHEEL +0 -0
- {plato_sdk_v2-2.8.6.dist-info → plato_sdk_v2-2.8.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
|
-
# filename:
|
|
3
|
-
# timestamp: 2026-02-
|
|
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")] =
|
|
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
|
|
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:
|
|
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")] =
|
|
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
|
|
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[
|
|
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
|
|
342
|
-
"""Extract
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
|
362
|
-
|
|
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
|
-
|
|
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]
|
|
551
|
+
console.print(f"[blue]Checking for local agent builds: {agent_images}[/blue]")
|
|
501
552
|
for agent_name in agent_images:
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|