plato-sdk-v2 2.0.64__py3-none-any.whl → 2.3.4__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.
Files changed (46) hide show
  1. plato/__init__.py +0 -9
  2. plato/_sims_generator/__init__.py +19 -4
  3. plato/_sims_generator/instruction.py +203 -0
  4. plato/_sims_generator/templates/instruction/helpers.py.jinja +161 -0
  5. plato/_sims_generator/templates/instruction/init.py.jinja +43 -0
  6. plato/agents/__init__.py +99 -430
  7. plato/agents/base.py +145 -0
  8. plato/agents/build.py +61 -0
  9. plato/agents/config.py +160 -0
  10. plato/agents/logging.py +515 -0
  11. plato/agents/runner.py +191 -0
  12. plato/agents/trajectory.py +266 -0
  13. plato/chronos/models/__init__.py +1 -1
  14. plato/sims/cli.py +299 -123
  15. plato/sims/registry.py +77 -4
  16. plato/v1/cli/agent.py +88 -84
  17. plato/v1/cli/pm.py +84 -44
  18. plato/v1/cli/sandbox.py +241 -61
  19. plato/v1/cli/ssh.py +16 -4
  20. plato/v1/cli/verify.py +685 -0
  21. plato/v1/cli/world.py +3 -0
  22. plato/v1/flow_executor.py +21 -17
  23. plato/v1/models/env.py +11 -11
  24. plato/v1/sdk.py +2 -2
  25. plato/v1/sync_env.py +11 -11
  26. plato/v1/sync_flow_executor.py +21 -17
  27. plato/v1/sync_sdk.py +4 -2
  28. plato/v2/__init__.py +2 -0
  29. plato/v2/async_/environment.py +31 -0
  30. plato/v2/async_/session.py +72 -4
  31. plato/v2/sync/environment.py +31 -0
  32. plato/v2/sync/session.py +72 -4
  33. plato/worlds/README.md +71 -56
  34. plato/worlds/__init__.py +56 -18
  35. plato/worlds/base.py +578 -93
  36. plato/worlds/config.py +276 -74
  37. plato/worlds/runner.py +475 -80
  38. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/METADATA +3 -3
  39. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/RECORD +41 -36
  40. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/entry_points.txt +1 -0
  41. plato/agents/callback.py +0 -246
  42. plato/world/__init__.py +0 -44
  43. plato/world/base.py +0 -267
  44. plato/world/config.py +0 -139
  45. plato/world/types.py +0 -47
  46. {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/WHEEL +0 -0
plato/v2/sync/session.py CHANGED
@@ -30,7 +30,9 @@ from plato._generated.api.v2.sessions import heartbeat as sessions_heartbeat
30
30
  from plato._generated.api.v2.sessions import make as sessions_make
31
31
  from plato._generated.api.v2.sessions import reset as sessions_reset
32
32
  from plato._generated.api.v2.sessions import set_date as sessions_set_date
33
+ from plato._generated.api.v2.sessions import setup_sandbox as sessions_setup_sandbox
33
34
  from plato._generated.api.v2.sessions import snapshot as sessions_snapshot
35
+ from plato._generated.api.v2.sessions import snapshot_store as sessions_snapshot_store
34
36
  from plato._generated.api.v2.sessions import state as sessions_state
35
37
  from plato._generated.api.v2.sessions import wait_for_ready as sessions_wait_for_ready
36
38
  from plato._generated.models import (
@@ -38,6 +40,8 @@ from plato._generated.models import (
38
40
  AppApiV2SchemasSessionCreateSnapshotResponse,
39
41
  AppApiV2SchemasSessionEvaluateResponse,
40
42
  AppApiV2SchemasSessionHeartbeatResponse,
43
+ AppApiV2SchemasSessionSetupSandboxRequest,
44
+ AppApiV2SchemasSessionSetupSandboxResponse,
41
45
  CreateDiskSnapshotRequest,
42
46
  CreateDiskSnapshotResponse,
43
47
  CreateSessionFromEnvs,
@@ -530,6 +534,38 @@ class Session:
530
534
  x_api_key=self._api_key,
531
535
  )
532
536
 
537
+ def setup_sandbox(
538
+ self,
539
+ timeout: int = 120,
540
+ ) -> AppApiV2SchemasSessionSetupSandboxResponse:
541
+ """Setup sandbox environment with Docker overlay on all environments.
542
+
543
+ This configures the VMs for Docker usage with overlay2 storage driver,
544
+ which is significantly faster than the default vfs driver. Should be called
545
+ after session creation and before pulling Docker images.
546
+
547
+ The setup includes:
548
+ - Mounting /dev/vdb to /mnt/docker for Docker storage
549
+ - Configuring Docker with overlay2 storage driver
550
+ - Setting up ECR and Docker Hub authentication
551
+ - Creating a docker-user service for non-root Docker access
552
+
553
+ Args:
554
+ timeout: Setup timeout in seconds (default: 120).
555
+
556
+ Returns:
557
+ SetupSandboxResponse with results per job_id.
558
+ """
559
+ self._check_closed()
560
+
561
+ request = AppApiV2SchemasSessionSetupSandboxRequest(timeout=timeout)
562
+ return sessions_setup_sandbox.sync(
563
+ client=self._http,
564
+ session_id=self.session_id,
565
+ body=request,
566
+ x_api_key=self._api_key,
567
+ )
568
+
533
569
  def evaluate(self, **kwargs) -> AppApiV2SchemasSessionEvaluateResponse:
534
570
  """Evaluate the session against task criteria.
535
571
 
@@ -560,6 +596,38 @@ class Session:
560
596
  x_api_key=self._api_key,
561
597
  )
562
598
 
599
+ def snapshot_store(
600
+ self,
601
+ override_service: str | None = None,
602
+ override_version: str | None = None,
603
+ override_dataset: str | None = None,
604
+ ) -> AppApiV2SchemasSessionCreateSnapshotResponse:
605
+ """Create a snapshot-store snapshot of all environments in the session.
606
+
607
+ Uses the snapshot-store pipeline for chunk-based deduplication and
608
+ efficient storage. This is the preferred method for new base snapshots.
609
+
610
+ Args:
611
+ override_service: Override simulator/service name in artifact metadata.
612
+ override_version: Override version/git_hash in artifact metadata.
613
+ override_dataset: Override dataset name in artifact metadata.
614
+
615
+ Returns:
616
+ Snapshot response with info per job_id.
617
+ """
618
+ self._check_closed()
619
+
620
+ return sessions_snapshot_store.sync(
621
+ client=self._http,
622
+ session_id=self.session_id,
623
+ body=AppApiV2SchemasSessionCreateSnapshotRequest(
624
+ override_service=override_service,
625
+ override_version=override_version,
626
+ override_dataset=override_dataset,
627
+ ),
628
+ x_api_key=self._api_key,
629
+ )
630
+
563
631
  def disk_snapshot(
564
632
  self,
565
633
  override_service: str | None = None,
@@ -625,10 +693,10 @@ class Session:
625
693
  """
626
694
  self._check_closed()
627
695
 
628
- try:
629
- from playwright.sync_api import Page
630
- except ImportError as e:
631
- raise ImportError("The login() method requires playwright. Install it with: pip install playwright") from e
696
+ import importlib.util
697
+
698
+ if importlib.util.find_spec("playwright") is None:
699
+ raise ImportError("The login() method requires playwright. Install it with: pip install playwright")
632
700
 
633
701
  context = browser.new_context()
634
702
  pages: dict[str, Page] = {}
plato/worlds/README.md CHANGED
@@ -6,15 +6,33 @@ Run Plato worlds locally for development and testing.
6
6
 
7
7
  ```bash
8
8
  # List available worlds
9
- plato-world-runner --list
9
+ plato-world-runner list
10
10
 
11
11
  # Run a world with a config file
12
- plato-world-runner --world <name> --config config.json
12
+ plato-world-runner run --world <name> --config config.json
13
13
  ```
14
14
 
15
15
  ## Config File Format
16
16
 
17
- Create a JSON config file with the following structure:
17
+ Create a JSON config file:
18
+
19
+ ```json
20
+ {
21
+ "repository_url": "https://github.com/example/repo",
22
+ "prompt": "Fix the bug in main.py",
23
+ "coder": {
24
+ "image": "my-agent:latest",
25
+ "config": {
26
+ "model": "gpt-4"
27
+ }
28
+ },
29
+ "git_token": "ghp_...",
30
+ "session_id": "local-test-001",
31
+ "callback_url": ""
32
+ }
33
+ ```
34
+
35
+ Or with nested format (backwards compatible):
18
36
 
19
37
  ```json
20
38
  {
@@ -24,62 +42,56 @@ Create a JSON config file with the following structure:
24
42
  },
25
43
  "agents": {
26
44
  "coder": {
27
- "image": "my-agent:latest",
28
- "config": {
29
- "model": "gpt-4"
30
- }
45
+ "image": "my-agent:latest"
31
46
  }
32
47
  },
33
48
  "secrets": {
34
- "OPENAI_API_KEY": "sk-..."
49
+ "git_token": "ghp_..."
35
50
  },
36
- "session_id": "local-test-001",
37
- "callback_url": ""
51
+ "session_id": "local-test-001"
38
52
  }
39
53
  ```
40
54
 
41
- ### Fields
42
-
43
- | Field | Description |
44
- |-------|-------------|
45
- | `world_config` | World-specific configuration (varies by world) |
46
- | `agents` | Map of slot name to agent config (`image` + optional `config`) |
47
- | `secrets` | Secret values (API keys, tokens) |
48
- | `session_id` | Unique identifier for this run |
49
- | `callback_url` | Full Chronos callback URL (e.g., `http://server/api/callback`), leave empty for local runs |
50
-
51
55
  ## Creating a World
52
56
 
53
- ### 1. Define the World Class
57
+ ### 1. Define the Config and World Class
54
58
 
55
59
  ```python
56
- # my_world.py
57
- from plato.worlds import BaseWorld, register_world, AgentSlot, Observation, StepResult
58
- from plato.worlds.config import RunConfig, WorldConfig
60
+ from typing import Annotated
61
+ from plato.worlds import (
62
+ BaseWorld, RunConfig, Agent, Secret, AgentConfig,
63
+ Observation, StepResult, register_world
64
+ )
59
65
 
60
- class MyWorldConfig(WorldConfig):
61
- """Typed config for MyWorld."""
66
+ class MyWorldConfig(RunConfig):
67
+ """Typed config - all fields accessible directly."""
68
+
69
+ # World-specific fields
62
70
  prompt: str
63
71
  max_steps: int = 10
64
72
 
73
+ # Agents (typed, no .get() needed)
74
+ worker: Annotated[AgentConfig, Agent(description="The main agent")]
75
+
76
+ # Secrets (typed, optional)
77
+ api_key: Annotated[str | None, Secret(description="API key")] = None
78
+
65
79
  @register_world("my-world")
66
- class MyWorld(BaseWorld):
80
+ class MyWorld(BaseWorld[MyWorldConfig]):
67
81
  name = "my-world"
68
82
  description = "A simple example world"
69
- agents = [
70
- AgentSlot(name="worker", description="The main agent", required=True),
71
- ]
72
- secrets = ["API_KEY"]
73
- config_class = MyWorldConfig
74
83
 
75
- async def reset(self, config: RunConfig[MyWorldConfig]) -> Observation:
76
- """Setup the world."""
77
- self.prompt = config.world_config.prompt
78
- return Observation(data={"prompt": self.prompt})
84
+ async def reset(self) -> Observation:
85
+ """Setup the world. Access config via self.config."""
86
+ # All access is typed - no .get() methods
87
+ prompt = self.config.prompt # str
88
+ worker = self.config.worker # AgentConfig
89
+ api_key = self.config.api_key # str | None
90
+
91
+ return Observation(data={"prompt": prompt})
79
92
 
80
93
  async def step(self) -> StepResult:
81
94
  """Execute one step."""
82
- # Your world logic here
83
95
  return StepResult(
84
96
  observation=Observation(data={"status": "done"}),
85
97
  done=True,
@@ -106,10 +118,10 @@ my-world = "my_world:MyWorld"
106
118
  pip install -e .
107
119
 
108
120
  # Verify it's registered
109
- plato-world-runner --list
121
+ plato-world-runner list
110
122
 
111
123
  # Run with config
112
- plato-world-runner --world my-world --config config.json -v
124
+ plato-world-runner run --world my-world --config config.json -v
113
125
  ```
114
126
 
115
127
  ## Programmatic Usage
@@ -117,12 +129,12 @@ plato-world-runner --world my-world --config config.json -v
117
129
  ```python
118
130
  import asyncio
119
131
  from plato.worlds import run_world
120
- from plato.worlds.config import RunConfig
132
+ from my_world import MyWorldConfig, AgentConfig
121
133
 
122
- config = RunConfig(
123
- world_config={"prompt": "Hello world"},
124
- agents={"worker": {"image": "agent:latest"}},
125
- secrets={"API_KEY": "secret"},
134
+ config = MyWorldConfig(
135
+ prompt="Hello world",
136
+ worker=AgentConfig(image="agent:latest"),
137
+ api_key="secret",
126
138
  )
127
139
 
128
140
  asyncio.run(run_world("my-world", config))
@@ -131,20 +143,23 @@ asyncio.run(run_world("my-world", config))
131
143
  Or load from a file:
132
144
 
133
145
  ```python
134
- from plato.worlds.config import RunConfig
146
+ from my_world import MyWorldConfig
135
147
 
136
- config = RunConfig.from_file("config.json")
148
+ config = MyWorldConfig.from_file("config.json")
137
149
  ```
138
150
 
139
151
  ## CLI Options
140
152
 
141
153
  ```
142
- plato-world-runner [OPTIONS]
154
+ plato-world-runner [COMMAND] [OPTIONS]
155
+
156
+ Commands:
157
+ run Run a world with the given configuration
158
+ list List available worlds
143
159
 
144
- Options:
145
- -w, --world TEXT World name to run
146
- -c, --config PATH Path to config JSON file
147
- -l, --list List available worlds
160
+ Run options:
161
+ -w, --world TEXT World name to run (required)
162
+ -c, --config PATH Path to config JSON file (required)
148
163
  -v, --verbose Enable debug logging
149
164
  ```
150
165
 
@@ -152,14 +167,14 @@ Options:
152
167
 
153
168
  1. **Discovery**: Worlds are discovered via `plato.worlds` entry points
154
169
  2. **Instantiation**: World class is instantiated
155
- 3. **Reset**: `reset(config)` is called to setup the world
170
+ 3. **Reset**: `reset()` is called to setup the world (config available via `self.config`)
156
171
  4. **Step Loop**: `step()` is called repeatedly until `done=True`
157
172
  5. **Cleanup**: `close()` is called to cleanup resources
158
173
 
159
174
  ```
160
- ┌─────────────────────────────────────────┐
161
- │ plato-world-runner --world X --config │
162
- └─────────────────────────────────────────┘
175
+ ┌───────────────────────────────────────────────┐
176
+ │ plato-world-runner run --world X --config Y
177
+ └───────────────────────────────────────────────┘
163
178
 
164
179
 
165
180
  ┌─────────────────┐
@@ -192,7 +207,7 @@ Options:
192
207
  Enable verbose logging:
193
208
 
194
209
  ```bash
195
- plato-world-runner --world my-world --config config.json --verbose
210
+ plato-world-runner run --world my-world --config config.json --verbose
196
211
  ```
197
212
 
198
213
  Or set log level in code:
plato/worlds/__init__.py CHANGED
@@ -1,44 +1,82 @@
1
- """Plato Worlds - simple world definitions for agent execution.
2
-
3
- A World defines:
4
- - Available agent slots (list of strings)
5
- - Configuration schema
6
- - Run logic (what happens when the world executes)
1
+ """Plato Worlds - typed world definitions for agent execution.
7
2
 
8
3
  Usage:
9
- from plato.worlds import BaseWorld, register_world, AgentSlot
4
+ from plato.worlds import BaseWorld, RunConfig, Agent, Secret, Env, AgentConfig, EnvConfig, register_world
5
+ from plato._generated.models import EnvFromArtifact, EnvFromSimulator
6
+ from typing import Annotated
7
+
8
+ class CodeWorldConfig(RunConfig):
9
+ # World-specific fields
10
+ repository_url: str
11
+ prompt: str
12
+
13
+ # Agents (typed)
14
+ coder: Annotated[AgentConfig, Agent(description="Coding agent")]
15
+
16
+ # Secrets (typed)
17
+ git_token: Annotated[str | None, Secret(description="GitHub token")] = None
18
+
19
+ # Environments (typed)
20
+ gitea: Annotated[EnvConfig, Env(description="Git server")] = EnvFromArtifact(
21
+ artifact_id="abc123",
22
+ alias="gitea",
23
+ )
10
24
 
11
25
  @register_world("code")
12
- class CodeWorld(BaseWorld):
13
- agents = ["coder"] # Available agent slots
26
+ class CodeWorld(BaseWorld[CodeWorldConfig]):
27
+ name = "code"
28
+ description = "Run coding agents"
29
+
30
+ async def reset(self) -> Observation:
31
+ # Fully typed access
32
+ url = self.config.repository_url
33
+ agent = self.config.coder
34
+ token = self.config.git_token
35
+ gitea = self.config.gitea # EnvConfig
14
36
 
15
- async def run(self, config: RunConfig) -> None:
16
- # Clone repo, run agent, etc.
17
- pass
37
+ async def step(self) -> StepResult:
38
+ ...
18
39
  """
19
40
 
41
+ from plato._generated.models import (
42
+ EnvFromArtifact,
43
+ EnvFromResource,
44
+ EnvFromSimulator,
45
+ )
20
46
  from plato.worlds.base import (
21
- AgentSlot,
22
47
  BaseWorld,
48
+ ConfigT,
23
49
  Observation,
24
50
  StepResult,
25
51
  get_registered_worlds,
26
52
  get_world,
27
53
  register_world,
28
54
  )
29
- from plato.worlds.config import AgentConfig, RunConfig, WorldConfig
55
+ from plato.worlds.config import Agent, AgentConfig, CheckpointConfig, Env, EnvConfig, RunConfig, Secret, StateConfig
30
56
  from plato.worlds.runner import run_world
31
57
 
32
58
  __all__ = [
59
+ # Base
33
60
  "BaseWorld",
34
- "AgentSlot",
61
+ "ConfigT",
35
62
  "Observation",
36
63
  "StepResult",
37
- "WorldConfig",
38
- "AgentConfig",
39
- "RunConfig",
40
64
  "register_world",
41
65
  "get_registered_worlds",
42
66
  "get_world",
67
+ # Config
68
+ "RunConfig",
69
+ "CheckpointConfig",
70
+ "StateConfig",
71
+ "AgentConfig",
72
+ "Agent",
73
+ "Secret",
74
+ "Env",
75
+ "EnvConfig",
76
+ # Env types (re-exported from generated models)
77
+ "EnvFromArtifact",
78
+ "EnvFromSimulator",
79
+ "EnvFromResource",
80
+ # Runner
43
81
  "run_world",
44
82
  ]