plato-sdk-v2 2.1.11__py3-none-any.whl → 2.2.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.
- plato/_sims_generator/__init__.py +19 -4
- plato/_sims_generator/instruction.py +203 -0
- plato/_sims_generator/templates/instruction/helpers.py.jinja +161 -0
- plato/_sims_generator/templates/instruction/init.py.jinja +43 -0
- plato/agents/__init__.py +15 -6
- plato/agents/logging.py +401 -0
- plato/agents/runner.py +98 -302
- plato/agents/trajectory.py +4 -4
- plato/chronos/models/__init__.py +1 -1
- plato/sims/cli.py +299 -123
- plato/sims/registry.py +77 -4
- plato/v1/cli/agent.py +10 -0
- plato/v1/cli/main.py +2 -0
- plato/v1/cli/pm.py +84 -44
- plato/v1/cli/sandbox.py +47 -9
- plato/v1/cli/sim.py +11 -0
- plato/v1/cli/verify.py +1269 -0
- plato/v1/cli/world.py +3 -0
- plato/v1/flow_executor.py +21 -17
- plato/v1/models/env.py +11 -11
- plato/v1/sdk.py +2 -2
- plato/v1/sync_env.py +11 -11
- plato/v1/sync_flow_executor.py +21 -17
- plato/v1/sync_sdk.py +4 -2
- plato/v2/async_/session.py +4 -4
- plato/v2/sync/session.py +4 -4
- plato/worlds/__init__.py +21 -2
- plato/worlds/base.py +222 -2
- plato/worlds/config.py +97 -7
- plato/worlds/runner.py +339 -1
- {plato_sdk_v2-2.1.11.dist-info → plato_sdk_v2-2.2.4.dist-info}/METADATA +1 -1
- {plato_sdk_v2-2.1.11.dist-info → plato_sdk_v2-2.2.4.dist-info}/RECORD +34 -29
- plato/agents/callback.py +0 -246
- {plato_sdk_v2-2.1.11.dist-info → plato_sdk_v2-2.2.4.dist-info}/WHEEL +0 -0
- {plato_sdk_v2-2.1.11.dist-info → plato_sdk_v2-2.2.4.dist-info}/entry_points.txt +0 -0
plato/agents/callback.py
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
"""Chronos callback utilities for agents.
|
|
2
|
-
|
|
3
|
-
This module provides utilities for agents to communicate with Chronos,
|
|
4
|
-
including pushing logs, uploading trajectories, and uploading zipped logs.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import base64
|
|
10
|
-
import io
|
|
11
|
-
import json
|
|
12
|
-
import logging
|
|
13
|
-
import zipfile
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
from typing import Any
|
|
16
|
-
|
|
17
|
-
import httpx
|
|
18
|
-
|
|
19
|
-
logger = logging.getLogger(__name__)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ChronosCallback:
|
|
23
|
-
"""Utility class for communicating with Chronos server.
|
|
24
|
-
|
|
25
|
-
Handles pushing logs, updating status, and uploading artifacts
|
|
26
|
-
(trajectory and zipped logs) to the Chronos callback endpoints.
|
|
27
|
-
|
|
28
|
-
Example:
|
|
29
|
-
callback = ChronosCallback(
|
|
30
|
-
callback_url="http://chronos.example.com/api/callback",
|
|
31
|
-
session_id="abc123",
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
# Push logs during execution
|
|
35
|
-
await callback.push_logs([
|
|
36
|
-
{"level": "info", "message": "Starting agent..."},
|
|
37
|
-
])
|
|
38
|
-
|
|
39
|
-
# After agent completes, upload artifacts
|
|
40
|
-
await callback.upload_artifacts(logs_dir="/path/to/logs")
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
def __init__(self, callback_url: str, session_id: str):
|
|
44
|
-
"""Initialize the callback client.
|
|
45
|
-
|
|
46
|
-
Args:
|
|
47
|
-
callback_url: Full callback base URL (e.g., http://server/api/callback)
|
|
48
|
-
session_id: The Chronos session ID for this run
|
|
49
|
-
"""
|
|
50
|
-
self.callback_url = callback_url.rstrip("/")
|
|
51
|
-
self.session_id = session_id
|
|
52
|
-
self._enabled = bool(callback_url and session_id)
|
|
53
|
-
|
|
54
|
-
@property
|
|
55
|
-
def enabled(self) -> bool:
|
|
56
|
-
"""Check if callbacks are enabled (both server and session_id set)."""
|
|
57
|
-
return self._enabled
|
|
58
|
-
|
|
59
|
-
async def push_logs(self, logs: list[dict[str, Any]]) -> bool:
|
|
60
|
-
"""Push log entries to Chronos.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
logs: List of log entries, each with 'level' and 'message' keys.
|
|
64
|
-
Optional keys: 'timestamp', 'extra'
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
True if logs were pushed successfully, False otherwise.
|
|
68
|
-
"""
|
|
69
|
-
if not self._enabled:
|
|
70
|
-
return False
|
|
71
|
-
|
|
72
|
-
try:
|
|
73
|
-
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
74
|
-
response = await client.post(
|
|
75
|
-
f"{self.callback_url}/logs",
|
|
76
|
-
json={"session_id": self.session_id, "logs": logs},
|
|
77
|
-
)
|
|
78
|
-
return response.status_code == 200
|
|
79
|
-
except Exception as e:
|
|
80
|
-
logger.warning(f"Failed to push logs to Chronos: {e}")
|
|
81
|
-
return False
|
|
82
|
-
|
|
83
|
-
async def push_log(
|
|
84
|
-
self,
|
|
85
|
-
message: str,
|
|
86
|
-
level: str = "info",
|
|
87
|
-
extra: dict[str, Any] | None = None,
|
|
88
|
-
) -> bool:
|
|
89
|
-
"""Push a single log entry to Chronos.
|
|
90
|
-
|
|
91
|
-
Args:
|
|
92
|
-
message: Log message
|
|
93
|
-
level: Log level (debug, info, warning, error)
|
|
94
|
-
extra: Optional additional structured data
|
|
95
|
-
|
|
96
|
-
Returns:
|
|
97
|
-
True if log was pushed successfully, False otherwise.
|
|
98
|
-
"""
|
|
99
|
-
log_entry: dict[str, Any] = {"level": level, "message": message}
|
|
100
|
-
if extra:
|
|
101
|
-
log_entry["extra"] = extra
|
|
102
|
-
return await self.push_logs([log_entry])
|
|
103
|
-
|
|
104
|
-
async def update_status(
|
|
105
|
-
self,
|
|
106
|
-
status: str,
|
|
107
|
-
message: str | None = None,
|
|
108
|
-
extra: dict[str, Any] | None = None,
|
|
109
|
-
) -> bool:
|
|
110
|
-
"""Update the session status in Chronos.
|
|
111
|
-
|
|
112
|
-
Args:
|
|
113
|
-
status: New status (running, completed, failed)
|
|
114
|
-
message: Optional status message
|
|
115
|
-
extra: Optional additional data
|
|
116
|
-
|
|
117
|
-
Returns:
|
|
118
|
-
True if status was updated successfully, False otherwise.
|
|
119
|
-
"""
|
|
120
|
-
if not self._enabled:
|
|
121
|
-
return False
|
|
122
|
-
|
|
123
|
-
try:
|
|
124
|
-
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
125
|
-
response = await client.post(
|
|
126
|
-
f"{self.callback_url}/status",
|
|
127
|
-
json={
|
|
128
|
-
"session_id": self.session_id,
|
|
129
|
-
"status": status,
|
|
130
|
-
"message": message,
|
|
131
|
-
"extra": extra,
|
|
132
|
-
},
|
|
133
|
-
)
|
|
134
|
-
return response.status_code == 200
|
|
135
|
-
except Exception as e:
|
|
136
|
-
logger.warning(f"Failed to update status in Chronos: {e}")
|
|
137
|
-
return False
|
|
138
|
-
|
|
139
|
-
def find_trajectory(self, logs_dir: str) -> dict[str, Any] | None:
|
|
140
|
-
"""Find and load ATIF trajectory from logs directory.
|
|
141
|
-
|
|
142
|
-
Agents write ATIF trajectory to /logs/agent/trajectory.json after
|
|
143
|
-
completing their run. This method finds and loads that file.
|
|
144
|
-
|
|
145
|
-
Args:
|
|
146
|
-
logs_dir: Path to the logs directory
|
|
147
|
-
|
|
148
|
-
Returns:
|
|
149
|
-
Parsed ATIF trajectory dict if found, None otherwise.
|
|
150
|
-
"""
|
|
151
|
-
trajectory_path = Path(logs_dir) / "agent" / "trajectory.json"
|
|
152
|
-
|
|
153
|
-
if not trajectory_path.exists():
|
|
154
|
-
return None
|
|
155
|
-
|
|
156
|
-
try:
|
|
157
|
-
with open(trajectory_path) as f:
|
|
158
|
-
data = json.load(f)
|
|
159
|
-
if isinstance(data, dict) and "schema_version" in data:
|
|
160
|
-
logger.info(f"Found ATIF trajectory: {trajectory_path}")
|
|
161
|
-
return data
|
|
162
|
-
return None
|
|
163
|
-
except Exception as e:
|
|
164
|
-
logger.warning(f"Failed to load trajectory from {trajectory_path}: {e}")
|
|
165
|
-
return None
|
|
166
|
-
|
|
167
|
-
def zip_logs_dir(self, logs_dir: str) -> bytes:
|
|
168
|
-
"""Zip the entire logs directory.
|
|
169
|
-
|
|
170
|
-
Args:
|
|
171
|
-
logs_dir: Path to the logs directory
|
|
172
|
-
|
|
173
|
-
Returns:
|
|
174
|
-
Zip file contents as bytes.
|
|
175
|
-
"""
|
|
176
|
-
logs_path = Path(logs_dir)
|
|
177
|
-
buffer = io.BytesIO()
|
|
178
|
-
|
|
179
|
-
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
180
|
-
for file_path in logs_path.rglob("*"):
|
|
181
|
-
if file_path.is_file():
|
|
182
|
-
arcname = file_path.relative_to(logs_path)
|
|
183
|
-
zf.write(file_path, arcname)
|
|
184
|
-
|
|
185
|
-
buffer.seek(0)
|
|
186
|
-
return buffer.read()
|
|
187
|
-
|
|
188
|
-
async def upload_artifacts(
|
|
189
|
-
self,
|
|
190
|
-
logs_dir: str,
|
|
191
|
-
trajectory: dict[str, Any] | None = None,
|
|
192
|
-
) -> bool:
|
|
193
|
-
"""Upload trajectory and zipped logs to Chronos.
|
|
194
|
-
|
|
195
|
-
If trajectory is not provided, attempts to find it in the logs directory.
|
|
196
|
-
The logs directory is zipped and uploaded to S3 via Chronos.
|
|
197
|
-
|
|
198
|
-
Args:
|
|
199
|
-
logs_dir: Path to the logs directory
|
|
200
|
-
trajectory: Optional pre-loaded trajectory dict. If None, will
|
|
201
|
-
attempt to find trajectory.json in logs_dir.
|
|
202
|
-
|
|
203
|
-
Returns:
|
|
204
|
-
True if artifacts were uploaded successfully, False otherwise.
|
|
205
|
-
"""
|
|
206
|
-
if not self._enabled:
|
|
207
|
-
return False
|
|
208
|
-
|
|
209
|
-
# Find trajectory if not provided
|
|
210
|
-
if trajectory is None:
|
|
211
|
-
trajectory = self.find_trajectory(logs_dir)
|
|
212
|
-
if trajectory:
|
|
213
|
-
logger.info("Found ATIF trajectory in logs directory")
|
|
214
|
-
else:
|
|
215
|
-
logger.info("No ATIF trajectory found in logs directory")
|
|
216
|
-
|
|
217
|
-
# Zip logs directory
|
|
218
|
-
logs_base64: str | None = None
|
|
219
|
-
try:
|
|
220
|
-
logs_zip = self.zip_logs_dir(logs_dir)
|
|
221
|
-
logs_base64 = base64.b64encode(logs_zip).decode("utf-8")
|
|
222
|
-
logger.info(f"Zipped logs: {len(logs_zip)} bytes")
|
|
223
|
-
except Exception as e:
|
|
224
|
-
logger.warning(f"Failed to zip logs: {e}")
|
|
225
|
-
|
|
226
|
-
# Upload to Chronos
|
|
227
|
-
try:
|
|
228
|
-
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
229
|
-
response = await client.post(
|
|
230
|
-
f"{self.callback_url}/artifacts",
|
|
231
|
-
json={
|
|
232
|
-
"session_id": self.session_id,
|
|
233
|
-
"trajectory": trajectory,
|
|
234
|
-
"logs_base64": logs_base64,
|
|
235
|
-
},
|
|
236
|
-
)
|
|
237
|
-
if response.status_code == 200:
|
|
238
|
-
result = response.json()
|
|
239
|
-
logger.info(f"Uploaded artifacts to Chronos: {result}")
|
|
240
|
-
return True
|
|
241
|
-
else:
|
|
242
|
-
logger.warning(f"Failed to upload artifacts: {response.status_code} {response.text}")
|
|
243
|
-
return False
|
|
244
|
-
except Exception as e:
|
|
245
|
-
logger.warning(f"Failed to upload artifacts to Chronos: {e}")
|
|
246
|
-
return False
|
|
File without changes
|
|
File without changes
|