plato-sdk-v2 2.5.1__py3-none-any.whl → 2.6.1__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/__init__.py +1 -1
- plato/_generated/api/v1/evals/get_scores_by_user.py +7 -0
- plato/_generated/api/v1/testcases/get_testcases.py +14 -0
- plato/_generated/api/v2/sessions/setup_sandbox.py +2 -2
- plato/_generated/models/__init__.py +42 -2
- plato/agents/runner.py +2 -33
- plato/chronos/api/admin/__init__.py +17 -0
- plato/chronos/api/admin/clear_database_api_admin_clear_db_post.py +57 -0
- plato/chronos/api/admin/sync_agents_api_admin_sync_agents_post.py +67 -0
- plato/chronos/api/admin/sync_all_api_admin_sync_all_post.py +67 -0
- plato/chronos/api/admin/sync_runtimes_api_admin_sync_runtimes_post.py +67 -0
- plato/chronos/api/admin/sync_worlds_api_admin_sync_worlds_post.py +67 -0
- plato/chronos/api/agents/list_agents.py +5 -5
- plato/chronos/api/checkpoints/__init__.py +8 -0
- plato/chronos/api/checkpoints/list_checkpoints.py +52 -0
- plato/chronos/api/checkpoints/preview_checkpoint.py +74 -0
- plato/chronos/api/events/__init__.py +8 -0
- plato/chronos/api/events/get_session_event.py +68 -0
- plato/chronos/api/events/list_session_events.py +62 -0
- plato/chronos/api/jobs/launch_job.py +8 -2
- plato/chronos/api/otel/__init__.py +8 -0
- plato/chronos/api/otel/get_session_traces_api_otel_sessions__session_id__traces_get.py +56 -0
- plato/chronos/api/otel/receive_traces_api_otel_v1_traces_post.py +49 -0
- plato/chronos/api/registry/list_registry_agents_api_registry_agents_get.py +5 -5
- plato/chronos/api/runtimes/__init__.py +2 -1
- plato/chronos/api/runtimes/get_runtime_logs.py +61 -0
- plato/chronos/api/sessions/__init__.py +24 -1
- plato/chronos/api/sessions/close_session.py +66 -0
- plato/chronos/api/sessions/complete_session.py +74 -0
- plato/chronos/api/sessions/create_session.py +69 -0
- plato/chronos/api/sessions/get_session.py +20 -2
- plato/chronos/api/sessions/get_session_bash_logs_download.py +61 -0
- plato/chronos/api/sessions/get_session_envs.py +62 -0
- plato/chronos/api/sessions/get_session_live_logs.py +62 -0
- plato/chronos/api/sessions/get_session_logs.py +3 -3
- plato/chronos/api/sessions/get_session_status.py +62 -0
- plato/chronos/api/sessions/list_sessions.py +20 -2
- plato/chronos/api/sessions/list_tags.py +80 -0
- plato/chronos/api/sessions/update_session_tags.py +68 -0
- plato/chronos/models/__init__.py +241 -196
- plato/v1/cli/chronos.py +66 -4
- plato/v2/__init__.py +8 -0
- plato/v2/async_/__init__.py +4 -0
- plato/v2/async_/chronos.py +419 -0
- plato/v2/sync/__init__.py +3 -0
- plato/v2/sync/chronos.py +419 -0
- plato/worlds/base.py +3 -3
- plato/worlds/config.py +3 -7
- {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/METADATA +1 -1
- {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/RECORD +52 -25
- {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/WHEEL +0 -0
- {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/entry_points.txt +0 -0
plato/v2/sync/chronos.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""Plato SDK v2 - Synchronous Chronos Client.
|
|
2
|
+
|
|
3
|
+
Provides high-level APIs for managing Chronos sessions and jobs programmatically.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import time
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import httpx
|
|
14
|
+
from dotenv import load_dotenv
|
|
15
|
+
|
|
16
|
+
from plato.chronos.api.jobs import launch_job
|
|
17
|
+
from plato.chronos.api.sessions import (
|
|
18
|
+
close_session,
|
|
19
|
+
complete_session,
|
|
20
|
+
get_session,
|
|
21
|
+
get_session_envs,
|
|
22
|
+
get_session_logs,
|
|
23
|
+
get_session_status,
|
|
24
|
+
list_sessions,
|
|
25
|
+
list_tags,
|
|
26
|
+
update_session_tags,
|
|
27
|
+
)
|
|
28
|
+
from plato.chronos.models import (
|
|
29
|
+
CompleteSessionRequest,
|
|
30
|
+
LaunchJobRequest,
|
|
31
|
+
LaunchJobResponse,
|
|
32
|
+
RuntimeConfig,
|
|
33
|
+
SessionEnvsResponse,
|
|
34
|
+
SessionListResponse,
|
|
35
|
+
SessionLogsResponse,
|
|
36
|
+
SessionResponse,
|
|
37
|
+
SessionStatusResponse,
|
|
38
|
+
TagsListResponse,
|
|
39
|
+
UpdateTagsRequest,
|
|
40
|
+
WorldConfig,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
load_dotenv()
|
|
44
|
+
|
|
45
|
+
logger = logging.getLogger(__name__)
|
|
46
|
+
|
|
47
|
+
DEFAULT_CHRONOS_URL = "https://chronos.plato.so"
|
|
48
|
+
DEFAULT_TIMEOUT = 120.0
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ChronosSession:
|
|
52
|
+
"""Wrapper for a Chronos session with convenient methods.
|
|
53
|
+
|
|
54
|
+
Provides methods to check status, get logs, update tags, and stop the session.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
http_client: httpx.Client,
|
|
60
|
+
api_key: str,
|
|
61
|
+
session_id: str,
|
|
62
|
+
plato_session_id: str | None = None,
|
|
63
|
+
):
|
|
64
|
+
self._http = http_client
|
|
65
|
+
self._api_key = api_key
|
|
66
|
+
self._session_id = session_id
|
|
67
|
+
self._plato_session_id = plato_session_id
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def session_id(self) -> str:
|
|
71
|
+
"""Get the Chronos session public ID."""
|
|
72
|
+
return self._session_id
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def plato_session_id(self) -> str | None:
|
|
76
|
+
"""Get the underlying Plato session ID."""
|
|
77
|
+
return self._plato_session_id
|
|
78
|
+
|
|
79
|
+
def get_status(self) -> SessionStatusResponse:
|
|
80
|
+
"""Get the current status of the session (lightweight).
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
SessionStatusResponse with status and status_reason.
|
|
84
|
+
"""
|
|
85
|
+
return get_session_status.sync(
|
|
86
|
+
client=self._http,
|
|
87
|
+
public_id=self._session_id,
|
|
88
|
+
x_api_key=self._api_key,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def get_details(self) -> SessionResponse:
|
|
92
|
+
"""Get full session details including trajectory and world config.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
SessionResponse with full session details.
|
|
96
|
+
"""
|
|
97
|
+
return get_session.sync(
|
|
98
|
+
client=self._http,
|
|
99
|
+
public_id=self._session_id,
|
|
100
|
+
x_api_key=self._api_key,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def get_envs(self) -> SessionEnvsResponse:
|
|
104
|
+
"""Get environment information for this session.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
SessionEnvsResponse with list of environments.
|
|
108
|
+
"""
|
|
109
|
+
return get_session_envs.sync(
|
|
110
|
+
client=self._http,
|
|
111
|
+
public_id=self._session_id,
|
|
112
|
+
x_api_key=self._api_key,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def get_logs(
|
|
116
|
+
self,
|
|
117
|
+
limit: int = 10000,
|
|
118
|
+
) -> SessionLogsResponse:
|
|
119
|
+
"""Get logs for this session.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
limit: Maximum number of log entries to return.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
SessionLogsResponse with log entries.
|
|
126
|
+
"""
|
|
127
|
+
return get_session_logs.sync(
|
|
128
|
+
client=self._http,
|
|
129
|
+
public_id=self._session_id,
|
|
130
|
+
limit=limit,
|
|
131
|
+
x_api_key=self._api_key,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def update_tags(self, tags: list[str]) -> SessionResponse:
|
|
135
|
+
"""Update tags for this session.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
tags: List of tags (use '.' for hierarchy, '_' instead of '-').
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Updated SessionResponse.
|
|
142
|
+
"""
|
|
143
|
+
# Normalize tags
|
|
144
|
+
normalized = [tag.replace("-", "_").replace(":", ".").replace(" ", "_") for tag in tags]
|
|
145
|
+
request = UpdateTagsRequest(tags=normalized)
|
|
146
|
+
return update_session_tags.sync(
|
|
147
|
+
client=self._http,
|
|
148
|
+
public_id=self._session_id,
|
|
149
|
+
body=request,
|
|
150
|
+
x_api_key=self._api_key,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def stop(self, error_message: str = "Cancelled by user") -> SessionResponse:
|
|
154
|
+
"""Stop/cancel this session.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
error_message: Reason for stopping.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Updated SessionResponse.
|
|
161
|
+
"""
|
|
162
|
+
request = CompleteSessionRequest(
|
|
163
|
+
status="cancelled",
|
|
164
|
+
error_message=error_message,
|
|
165
|
+
)
|
|
166
|
+
return complete_session.sync(
|
|
167
|
+
client=self._http,
|
|
168
|
+
public_id=self._session_id,
|
|
169
|
+
body=request,
|
|
170
|
+
x_api_key=self._api_key,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def complete(
|
|
174
|
+
self,
|
|
175
|
+
status: str = "completed",
|
|
176
|
+
exit_code: int | None = None,
|
|
177
|
+
error_message: str | None = None,
|
|
178
|
+
) -> SessionResponse:
|
|
179
|
+
"""Mark session as completed or failed.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
status: Final status ('completed', 'failed', or 'cancelled').
|
|
183
|
+
exit_code: Optional exit code from world runner.
|
|
184
|
+
error_message: Error message if failed.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Updated SessionResponse.
|
|
188
|
+
"""
|
|
189
|
+
request = CompleteSessionRequest(
|
|
190
|
+
status=status,
|
|
191
|
+
exit_code=exit_code,
|
|
192
|
+
error_message=error_message,
|
|
193
|
+
)
|
|
194
|
+
return complete_session.sync(
|
|
195
|
+
client=self._http,
|
|
196
|
+
public_id=self._session_id,
|
|
197
|
+
body=request,
|
|
198
|
+
x_api_key=self._api_key,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def close(self) -> None:
|
|
202
|
+
"""Close the Plato session (release VM resources).
|
|
203
|
+
|
|
204
|
+
Note: This closes the underlying Plato session, not just the Chronos record.
|
|
205
|
+
"""
|
|
206
|
+
close_session.sync(
|
|
207
|
+
client=self._http,
|
|
208
|
+
public_id=self._session_id,
|
|
209
|
+
x_api_key=self._api_key,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def wait_until_complete(
|
|
213
|
+
self,
|
|
214
|
+
timeout: float = 3600.0,
|
|
215
|
+
poll_interval: float = 5.0,
|
|
216
|
+
) -> SessionResponse:
|
|
217
|
+
"""Wait until the session reaches a terminal state.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
timeout: Maximum time to wait in seconds.
|
|
221
|
+
poll_interval: Time between status checks.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Final SessionResponse.
|
|
225
|
+
|
|
226
|
+
Raises:
|
|
227
|
+
TimeoutError: If session doesn't complete within timeout.
|
|
228
|
+
"""
|
|
229
|
+
terminal_statuses = {"completed", "failed", "cancelled", "error"}
|
|
230
|
+
elapsed = 0.0
|
|
231
|
+
|
|
232
|
+
while elapsed < timeout:
|
|
233
|
+
status_response = self.get_status()
|
|
234
|
+
if status_response.status in terminal_statuses:
|
|
235
|
+
return self.get_details()
|
|
236
|
+
|
|
237
|
+
time.sleep(poll_interval)
|
|
238
|
+
elapsed += poll_interval
|
|
239
|
+
|
|
240
|
+
raise TimeoutError(f"Session {self._session_id} did not complete within {timeout} seconds")
|
|
241
|
+
|
|
242
|
+
def __repr__(self) -> str:
|
|
243
|
+
return f"ChronosSession(session_id={self._session_id!r})"
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class Chronos:
|
|
247
|
+
"""Synchronous client for Chronos job management API.
|
|
248
|
+
|
|
249
|
+
Provides high-level methods for launching jobs, managing sessions,
|
|
250
|
+
and monitoring job status.
|
|
251
|
+
|
|
252
|
+
Usage:
|
|
253
|
+
from plato.v2.sync import Chronos
|
|
254
|
+
|
|
255
|
+
with Chronos() as chronos:
|
|
256
|
+
# Launch a job
|
|
257
|
+
session = chronos.launch(
|
|
258
|
+
world_package="plato-world-computer-use",
|
|
259
|
+
world_config={"task": "Navigate to google.com"},
|
|
260
|
+
tags=["test", "project.my_project"],
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Wait for completion
|
|
264
|
+
result = session.wait_until_complete()
|
|
265
|
+
print(f"Status: {result.status}")
|
|
266
|
+
|
|
267
|
+
# Or poll manually
|
|
268
|
+
while True:
|
|
269
|
+
status = session.get_status()
|
|
270
|
+
if status.status in ("completed", "failed"):
|
|
271
|
+
break
|
|
272
|
+
time.sleep(5)
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
def __init__(
|
|
276
|
+
self,
|
|
277
|
+
api_key: str | None = None,
|
|
278
|
+
base_url: str | None = None,
|
|
279
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
280
|
+
):
|
|
281
|
+
"""Initialize the Chronos client.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
api_key: Plato API key. Falls back to PLATO_API_KEY env var.
|
|
285
|
+
base_url: Chronos API base URL. Falls back to CHRONOS_URL env var.
|
|
286
|
+
timeout: Request timeout in seconds.
|
|
287
|
+
"""
|
|
288
|
+
resolved_api_key = api_key or os.environ.get("PLATO_API_KEY")
|
|
289
|
+
if not resolved_api_key:
|
|
290
|
+
raise ValueError("API key required. Set PLATO_API_KEY or pass api_key=")
|
|
291
|
+
self._api_key: str = resolved_api_key
|
|
292
|
+
|
|
293
|
+
url = base_url or os.environ.get("CHRONOS_URL", DEFAULT_CHRONOS_URL)
|
|
294
|
+
self.base_url = url.rstrip("/")
|
|
295
|
+
self.timeout = timeout
|
|
296
|
+
|
|
297
|
+
self._http = httpx.Client(
|
|
298
|
+
base_url=self.base_url,
|
|
299
|
+
timeout=httpx.Timeout(timeout),
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
def launch(
|
|
303
|
+
self,
|
|
304
|
+
world_package: str,
|
|
305
|
+
world_config: dict[str, Any] | None = None,
|
|
306
|
+
runtime_artifact_id: str | None = None,
|
|
307
|
+
tags: list[str] | None = None,
|
|
308
|
+
) -> ChronosSession:
|
|
309
|
+
"""Launch a new Chronos job.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
world_package: World package name with optional version
|
|
313
|
+
(e.g., "plato-world-computer-use:0.1.0").
|
|
314
|
+
world_config: Configuration passed to the world runner.
|
|
315
|
+
runtime_artifact_id: Optional runtime artifact ID for cached environment.
|
|
316
|
+
tags: Optional tags for organizing sessions (use '.' for hierarchy).
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
ChronosSession for monitoring and managing the job.
|
|
320
|
+
|
|
321
|
+
Example:
|
|
322
|
+
session = chronos.launch(
|
|
323
|
+
world_package="plato-world-computer-use",
|
|
324
|
+
world_config={
|
|
325
|
+
"task": "Navigate to google.com",
|
|
326
|
+
"agents": [{"name": "computer-use", "version": "latest"}],
|
|
327
|
+
},
|
|
328
|
+
tags=["project.my_project", "env.dev"],
|
|
329
|
+
)
|
|
330
|
+
"""
|
|
331
|
+
# Normalize tags
|
|
332
|
+
normalized_tags = None
|
|
333
|
+
if tags:
|
|
334
|
+
normalized_tags = [tag.replace("-", "_").replace(":", ".").replace(" ", "_") for tag in tags]
|
|
335
|
+
|
|
336
|
+
request = LaunchJobRequest(
|
|
337
|
+
world=WorldConfig(
|
|
338
|
+
package=world_package,
|
|
339
|
+
config=world_config,
|
|
340
|
+
),
|
|
341
|
+
runtime=RuntimeConfig(artifact_id=runtime_artifact_id) if runtime_artifact_id else None,
|
|
342
|
+
tags=normalized_tags,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
response: LaunchJobResponse = launch_job.sync(
|
|
346
|
+
client=self._http,
|
|
347
|
+
body=request,
|
|
348
|
+
x_api_key=self._api_key,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
logger.info(f"Launched Chronos job: {response.session_id}")
|
|
352
|
+
|
|
353
|
+
return ChronosSession(
|
|
354
|
+
http_client=self._http,
|
|
355
|
+
api_key=self.api_key,
|
|
356
|
+
session_id=response.session_id,
|
|
357
|
+
plato_session_id=response.plato_session_id,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
def get_session(self, session_id: str) -> ChronosSession:
|
|
361
|
+
"""Get a ChronosSession wrapper for an existing session.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
session_id: The Chronos session public ID.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
ChronosSession for the specified session.
|
|
368
|
+
"""
|
|
369
|
+
# Verify the session exists by fetching status
|
|
370
|
+
get_session_status.sync(
|
|
371
|
+
client=self._http,
|
|
372
|
+
public_id=session_id,
|
|
373
|
+
x_api_key=self._api_key,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
return ChronosSession(
|
|
377
|
+
http_client=self._http,
|
|
378
|
+
api_key=self.api_key,
|
|
379
|
+
session_id=session_id,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
def list_sessions(
|
|
383
|
+
self,
|
|
384
|
+
tag: str | None = None,
|
|
385
|
+
) -> SessionListResponse:
|
|
386
|
+
"""List Chronos sessions.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
tag: Filter by tag (fuzzy substring match).
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
SessionListResponse with list of sessions.
|
|
393
|
+
"""
|
|
394
|
+
return list_sessions.sync(
|
|
395
|
+
client=self._http,
|
|
396
|
+
tag=tag,
|
|
397
|
+
x_api_key=self._api_key,
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
def list_tags(self) -> TagsListResponse:
|
|
401
|
+
"""List all unique tags across sessions.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
TagsListResponse with list of tags.
|
|
405
|
+
"""
|
|
406
|
+
return list_tags.sync(
|
|
407
|
+
client=self._http,
|
|
408
|
+
x_api_key=self._api_key,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def close(self) -> None:
|
|
412
|
+
"""Close the underlying HTTP client."""
|
|
413
|
+
self._http.close()
|
|
414
|
+
|
|
415
|
+
def __enter__(self) -> Chronos:
|
|
416
|
+
return self
|
|
417
|
+
|
|
418
|
+
def __exit__(self, *args: Any) -> None:
|
|
419
|
+
self.close()
|
plato/worlds/base.py
CHANGED
|
@@ -227,7 +227,6 @@ class BaseWorld(ABC, Generic[ConfigT]):
|
|
|
227
227
|
self,
|
|
228
228
|
image: str,
|
|
229
229
|
config: dict,
|
|
230
|
-
secrets: dict[str, str],
|
|
231
230
|
instruction: str,
|
|
232
231
|
workspace: str | None = None,
|
|
233
232
|
logs_dir: str | None = None,
|
|
@@ -241,7 +240,6 @@ class BaseWorld(ABC, Generic[ConfigT]):
|
|
|
241
240
|
Args:
|
|
242
241
|
image: Docker image URI
|
|
243
242
|
config: Agent configuration dict
|
|
244
|
-
secrets: Secret values (API keys, etc.)
|
|
245
243
|
instruction: Task instruction for the agent
|
|
246
244
|
workspace: Docker volume name for workspace
|
|
247
245
|
logs_dir: Ignored (kept for backwards compatibility)
|
|
@@ -249,11 +247,13 @@ class BaseWorld(ABC, Generic[ConfigT]):
|
|
|
249
247
|
|
|
250
248
|
Returns:
|
|
251
249
|
The container name that was created
|
|
250
|
+
|
|
251
|
+
Note: Common API key environment variables (ANTHROPIC_API_KEY, etc.)
|
|
252
|
+
are automatically forwarded to the agent container.
|
|
252
253
|
"""
|
|
253
254
|
container_name = await _run_agent_raw(
|
|
254
255
|
image=image,
|
|
255
256
|
config=config,
|
|
256
|
-
secrets=secrets,
|
|
257
257
|
instruction=instruction,
|
|
258
258
|
workspace=workspace,
|
|
259
259
|
logs_dir=logs_dir,
|
plato/worlds/config.py
CHANGED
|
@@ -153,7 +153,6 @@ class RunConfig(BaseModel):
|
|
|
153
153
|
session_id: str = ""
|
|
154
154
|
otel_url: str = "" # OTel endpoint URL
|
|
155
155
|
upload_url: str = "" # Presigned S3 URL for uploads
|
|
156
|
-
all_secrets: dict[str, str] = Field(default_factory=dict) # All secrets (world + agent)
|
|
157
156
|
|
|
158
157
|
# Serialized Plato session for connecting to VM and sending heartbeats
|
|
159
158
|
# This is the output of Session.dump() - used to restore session with Session.load()
|
|
@@ -203,7 +202,7 @@ class RunConfig(BaseModel):
|
|
|
203
202
|
env_list_field: dict | None = None # For EnvList marker (arbitrary envs)
|
|
204
203
|
|
|
205
204
|
# Skip runtime fields
|
|
206
|
-
runtime_fields = {"session_id", "otel_url", "upload_url", "
|
|
205
|
+
runtime_fields = {"session_id", "otel_url", "upload_url", "plato_session", "checkpoint", "state"}
|
|
207
206
|
|
|
208
207
|
for field_name, prop_schema in properties.items():
|
|
209
208
|
if field_name in runtime_fields:
|
|
@@ -319,8 +318,8 @@ class RunConfig(BaseModel):
|
|
|
319
318
|
# Handle agents dict -> individual agent fields
|
|
320
319
|
agents_dict = data.pop("agents", {})
|
|
321
320
|
|
|
322
|
-
# Handle secrets dict -> individual secret fields
|
|
323
|
-
secrets_dict = data.pop("secrets", {})
|
|
321
|
+
# Handle secrets dict -> individual secret fields (for schema validation)
|
|
322
|
+
secrets_dict = data.pop("secrets", {}) # Pop but don't store separately
|
|
324
323
|
|
|
325
324
|
# Check if there's an EnvList field - if so, don't pop envs as a dict
|
|
326
325
|
has_env_list = any(isinstance(m, EnvList) for m in annotations.values())
|
|
@@ -356,9 +355,6 @@ class RunConfig(BaseModel):
|
|
|
356
355
|
if isinstance(env_list, list):
|
|
357
356
|
parsed[field_name] = [_parse_env_config(e) if isinstance(e, dict) else e for e in env_list]
|
|
358
357
|
|
|
359
|
-
# Store all secrets for agent use
|
|
360
|
-
parsed["all_secrets"] = secrets_dict
|
|
361
|
-
|
|
362
358
|
return cls(**parsed)
|
|
363
359
|
|
|
364
360
|
|