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.
Files changed (52) hide show
  1. plato/_generated/__init__.py +1 -1
  2. plato/_generated/api/v1/evals/get_scores_by_user.py +7 -0
  3. plato/_generated/api/v1/testcases/get_testcases.py +14 -0
  4. plato/_generated/api/v2/sessions/setup_sandbox.py +2 -2
  5. plato/_generated/models/__init__.py +42 -2
  6. plato/agents/runner.py +2 -33
  7. plato/chronos/api/admin/__init__.py +17 -0
  8. plato/chronos/api/admin/clear_database_api_admin_clear_db_post.py +57 -0
  9. plato/chronos/api/admin/sync_agents_api_admin_sync_agents_post.py +67 -0
  10. plato/chronos/api/admin/sync_all_api_admin_sync_all_post.py +67 -0
  11. plato/chronos/api/admin/sync_runtimes_api_admin_sync_runtimes_post.py +67 -0
  12. plato/chronos/api/admin/sync_worlds_api_admin_sync_worlds_post.py +67 -0
  13. plato/chronos/api/agents/list_agents.py +5 -5
  14. plato/chronos/api/checkpoints/__init__.py +8 -0
  15. plato/chronos/api/checkpoints/list_checkpoints.py +52 -0
  16. plato/chronos/api/checkpoints/preview_checkpoint.py +74 -0
  17. plato/chronos/api/events/__init__.py +8 -0
  18. plato/chronos/api/events/get_session_event.py +68 -0
  19. plato/chronos/api/events/list_session_events.py +62 -0
  20. plato/chronos/api/jobs/launch_job.py +8 -2
  21. plato/chronos/api/otel/__init__.py +8 -0
  22. plato/chronos/api/otel/get_session_traces_api_otel_sessions__session_id__traces_get.py +56 -0
  23. plato/chronos/api/otel/receive_traces_api_otel_v1_traces_post.py +49 -0
  24. plato/chronos/api/registry/list_registry_agents_api_registry_agents_get.py +5 -5
  25. plato/chronos/api/runtimes/__init__.py +2 -1
  26. plato/chronos/api/runtimes/get_runtime_logs.py +61 -0
  27. plato/chronos/api/sessions/__init__.py +24 -1
  28. plato/chronos/api/sessions/close_session.py +66 -0
  29. plato/chronos/api/sessions/complete_session.py +74 -0
  30. plato/chronos/api/sessions/create_session.py +69 -0
  31. plato/chronos/api/sessions/get_session.py +20 -2
  32. plato/chronos/api/sessions/get_session_bash_logs_download.py +61 -0
  33. plato/chronos/api/sessions/get_session_envs.py +62 -0
  34. plato/chronos/api/sessions/get_session_live_logs.py +62 -0
  35. plato/chronos/api/sessions/get_session_logs.py +3 -3
  36. plato/chronos/api/sessions/get_session_status.py +62 -0
  37. plato/chronos/api/sessions/list_sessions.py +20 -2
  38. plato/chronos/api/sessions/list_tags.py +80 -0
  39. plato/chronos/api/sessions/update_session_tags.py +68 -0
  40. plato/chronos/models/__init__.py +241 -196
  41. plato/v1/cli/chronos.py +66 -4
  42. plato/v2/__init__.py +8 -0
  43. plato/v2/async_/__init__.py +4 -0
  44. plato/v2/async_/chronos.py +419 -0
  45. plato/v2/sync/__init__.py +3 -0
  46. plato/v2/sync/chronos.py +419 -0
  47. plato/worlds/base.py +3 -3
  48. plato/worlds/config.py +3 -7
  49. {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/METADATA +1 -1
  50. {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/RECORD +52 -25
  51. {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/WHEEL +0 -0
  52. {plato_sdk_v2-2.5.1.dist-info → plato_sdk_v2-2.6.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,52 @@
1
+ """List Checkpoints"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import CheckpointListResponse
11
+
12
+
13
+ def _build_request_args(
14
+ session_id: str,
15
+ ) -> dict[str, Any]:
16
+ """Build request arguments."""
17
+ url = f"/api/checkpoints/session/{session_id}"
18
+
19
+ return {
20
+ "method": "GET",
21
+ "url": url,
22
+ }
23
+
24
+
25
+ def sync(
26
+ client: httpx.Client,
27
+ session_id: str,
28
+ ) -> CheckpointListResponse:
29
+ """List all checkpoints for a Chronos session."""
30
+
31
+ request_args = _build_request_args(
32
+ session_id=session_id,
33
+ )
34
+
35
+ response = client.request(**request_args)
36
+ raise_for_status(response)
37
+ return CheckpointListResponse.model_validate(response.json())
38
+
39
+
40
+ async def asyncio(
41
+ client: httpx.AsyncClient,
42
+ session_id: str,
43
+ ) -> CheckpointListResponse:
44
+ """List all checkpoints for a Chronos session."""
45
+
46
+ request_args = _build_request_args(
47
+ session_id=session_id,
48
+ )
49
+
50
+ response = await client.request(**request_args)
51
+ raise_for_status(response)
52
+ return CheckpointListResponse.model_validate(response.json())
@@ -0,0 +1,74 @@
1
+ """Preview Checkpoint"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import PreviewResponse
11
+
12
+
13
+ def _build_request_args(
14
+ checkpoint_id: str,
15
+ ) -> dict[str, Any]:
16
+ """Build request arguments."""
17
+ url = f"/api/checkpoints/{checkpoint_id}/preview"
18
+
19
+ return {
20
+ "method": "POST",
21
+ "url": url,
22
+ }
23
+
24
+
25
+ def sync(
26
+ client: httpx.Client,
27
+ checkpoint_id: str,
28
+ ) -> PreviewResponse:
29
+ """Launch a preview session from a checkpoint.
30
+
31
+ Creates an ephemeral Plato session using the checkpoint's artifact IDs.
32
+ Returns serialized session data that can be used with Session.load()
33
+ to send heartbeats and eventually close the session.
34
+
35
+ The frontend should:
36
+ 1. Call this endpoint to get the serialized session
37
+ 2. Use Session.load(serialized_session) to restore the session
38
+ 3. Call session.start_heartbeat() to keep envs alive
39
+ 4. Display env URLs/job IDs in a modal
40
+ 5. Call session.stop_heartbeat() and session.close() when done"""
41
+
42
+ request_args = _build_request_args(
43
+ checkpoint_id=checkpoint_id,
44
+ )
45
+
46
+ response = client.request(**request_args)
47
+ raise_for_status(response)
48
+ return PreviewResponse.model_validate(response.json())
49
+
50
+
51
+ async def asyncio(
52
+ client: httpx.AsyncClient,
53
+ checkpoint_id: str,
54
+ ) -> PreviewResponse:
55
+ """Launch a preview session from a checkpoint.
56
+
57
+ Creates an ephemeral Plato session using the checkpoint's artifact IDs.
58
+ Returns serialized session data that can be used with Session.load()
59
+ to send heartbeats and eventually close the session.
60
+
61
+ The frontend should:
62
+ 1. Call this endpoint to get the serialized session
63
+ 2. Use Session.load(serialized_session) to restore the session
64
+ 3. Call session.start_heartbeat() to keep envs alive
65
+ 4. Display env URLs/job IDs in a modal
66
+ 5. Call session.stop_heartbeat() and session.close() when done"""
67
+
68
+ request_args = _build_request_args(
69
+ checkpoint_id=checkpoint_id,
70
+ )
71
+
72
+ response = await client.request(**request_args)
73
+ raise_for_status(response)
74
+ return PreviewResponse.model_validate(response.json())
@@ -0,0 +1,8 @@
1
+ """API endpoints."""
2
+
3
+ from . import get_session_event, list_session_events
4
+
5
+ __all__ = [
6
+ "list_session_events",
7
+ "get_session_event",
8
+ ]
@@ -0,0 +1,68 @@
1
+ """Get Event"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import OTelSpan
11
+
12
+
13
+ def _build_request_args(
14
+ span_id: str,
15
+ x_api_key: str | None = None,
16
+ ) -> dict[str, Any]:
17
+ """Build request arguments."""
18
+ url = f"/api/events/{span_id}"
19
+
20
+ headers: dict[str, str] = {}
21
+ if x_api_key is not None:
22
+ headers["X-API-Key"] = x_api_key
23
+
24
+ return {
25
+ "method": "GET",
26
+ "url": url,
27
+ "headers": headers,
28
+ }
29
+
30
+
31
+ def sync(
32
+ client: httpx.Client,
33
+ span_id: str,
34
+ x_api_key: str | None = None,
35
+ ) -> OTelSpan:
36
+ """Get a span by ID.
37
+
38
+ Note: This requires scanning all batches, so it's not efficient.
39
+ Consider caching or indexing spans if this is used frequently."""
40
+
41
+ request_args = _build_request_args(
42
+ span_id=span_id,
43
+ x_api_key=x_api_key,
44
+ )
45
+
46
+ response = client.request(**request_args)
47
+ raise_for_status(response)
48
+ return OTelSpan.model_validate(response.json())
49
+
50
+
51
+ async def asyncio(
52
+ client: httpx.AsyncClient,
53
+ span_id: str,
54
+ x_api_key: str | None = None,
55
+ ) -> OTelSpan:
56
+ """Get a span by ID.
57
+
58
+ Note: This requires scanning all batches, so it's not efficient.
59
+ Consider caching or indexing spans if this is used frequently."""
60
+
61
+ request_args = _build_request_args(
62
+ span_id=span_id,
63
+ x_api_key=x_api_key,
64
+ )
65
+
66
+ response = await client.request(**request_args)
67
+ raise_for_status(response)
68
+ return OTelSpan.model_validate(response.json())
@@ -0,0 +1,62 @@
1
+ """List Events For Session"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import OTelSpanListResponse
11
+
12
+
13
+ def _build_request_args(
14
+ session_public_id: str,
15
+ x_api_key: str | None = None,
16
+ ) -> dict[str, Any]:
17
+ """Build request arguments."""
18
+ url = f"/api/events/session/{session_public_id}"
19
+
20
+ headers: dict[str, str] = {}
21
+ if x_api_key is not None:
22
+ headers["X-API-Key"] = x_api_key
23
+
24
+ return {
25
+ "method": "GET",
26
+ "url": url,
27
+ "headers": headers,
28
+ }
29
+
30
+
31
+ def sync(
32
+ client: httpx.Client,
33
+ session_public_id: str,
34
+ x_api_key: str | None = None,
35
+ ) -> OTelSpanListResponse:
36
+ """List all OTel spans for a session."""
37
+
38
+ request_args = _build_request_args(
39
+ session_public_id=session_public_id,
40
+ x_api_key=x_api_key,
41
+ )
42
+
43
+ response = client.request(**request_args)
44
+ raise_for_status(response)
45
+ return OTelSpanListResponse.model_validate(response.json())
46
+
47
+
48
+ async def asyncio(
49
+ client: httpx.AsyncClient,
50
+ session_public_id: str,
51
+ x_api_key: str | None = None,
52
+ ) -> OTelSpanListResponse:
53
+ """List all OTel spans for a session."""
54
+
55
+ request_args = _build_request_args(
56
+ session_public_id=session_public_id,
57
+ x_api_key=x_api_key,
58
+ )
59
+
60
+ response = await client.request(**request_args)
61
+ raise_for_status(response)
62
+ return OTelSpanListResponse.model_validate(response.json())
@@ -34,7 +34,10 @@ def sync(
34
34
  body: LaunchJobRequest,
35
35
  x_api_key: str | None = None,
36
36
  ) -> LaunchJobResponse:
37
- """Launch a new Chronos job."""
37
+ """Launch a new Chronos job.
38
+
39
+ The world.config is passed directly to the world runner.
40
+ Agent and secret configs should be embedded in world.config."""
38
41
 
39
42
  request_args = _build_request_args(
40
43
  body=body,
@@ -51,7 +54,10 @@ async def asyncio(
51
54
  body: LaunchJobRequest,
52
55
  x_api_key: str | None = None,
53
56
  ) -> LaunchJobResponse:
54
- """Launch a new Chronos job."""
57
+ """Launch a new Chronos job.
58
+
59
+ The world.config is passed directly to the world runner.
60
+ Agent and secret configs should be embedded in world.config."""
55
61
 
56
62
  request_args = _build_request_args(
57
63
  body=body,
@@ -0,0 +1,8 @@
1
+ """API endpoints."""
2
+
3
+ from . import get_session_traces_api_otel_sessions__session_id__traces_get, receive_traces_api_otel_v1_traces_post
4
+
5
+ __all__ = [
6
+ "receive_traces_api_otel_v1_traces_post",
7
+ "get_session_traces_api_otel_sessions__session_id__traces_get",
8
+ ]
@@ -0,0 +1,56 @@
1
+ """Get Session Traces"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import OTelTraceResponse
11
+
12
+
13
+ def _build_request_args(
14
+ session_id: str,
15
+ ) -> dict[str, Any]:
16
+ """Build request arguments."""
17
+ url = f"/api/otel/sessions/{session_id}/traces"
18
+
19
+ return {
20
+ "method": "GET",
21
+ "url": url,
22
+ }
23
+
24
+
25
+ def sync(
26
+ client: httpx.Client,
27
+ session_id: str,
28
+ ) -> OTelTraceResponse:
29
+ """Get all parsed traces for a session.
30
+
31
+ Returns spans parsed from stored OTLP batches, suitable for UI rendering."""
32
+
33
+ request_args = _build_request_args(
34
+ session_id=session_id,
35
+ )
36
+
37
+ response = client.request(**request_args)
38
+ raise_for_status(response)
39
+ return OTelTraceResponse.model_validate(response.json())
40
+
41
+
42
+ async def asyncio(
43
+ client: httpx.AsyncClient,
44
+ session_id: str,
45
+ ) -> OTelTraceResponse:
46
+ """Get all parsed traces for a session.
47
+
48
+ Returns spans parsed from stored OTLP batches, suitable for UI rendering."""
49
+
50
+ request_args = _build_request_args(
51
+ session_id=session_id,
52
+ )
53
+
54
+ response = await client.request(**request_args)
55
+ raise_for_status(response)
56
+ return OTelTraceResponse.model_validate(response.json())
@@ -0,0 +1,49 @@
1
+ """Receive Traces"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+
11
+
12
+ def _build_request_args() -> dict[str, Any]:
13
+ """Build request arguments."""
14
+ url = "/api/otel/v1/traces"
15
+
16
+ return {
17
+ "method": "POST",
18
+ "url": url,
19
+ }
20
+
21
+
22
+ def sync(
23
+ client: httpx.Client,
24
+ ) -> dict[str, Any]:
25
+ """Receive OTLP trace data (JSON or protobuf) and store as JSON.
26
+
27
+ Resource attributes must include:
28
+ - plato.session.id: The Chronos session ID"""
29
+
30
+ request_args = _build_request_args()
31
+
32
+ response = client.request(**request_args)
33
+ raise_for_status(response)
34
+ return response.json()
35
+
36
+
37
+ async def asyncio(
38
+ client: httpx.AsyncClient,
39
+ ) -> dict[str, Any]:
40
+ """Receive OTLP trace data (JSON or protobuf) and store as JSON.
41
+
42
+ Resource attributes must include:
43
+ - plato.session.id: The Chronos session ID"""
44
+
45
+ request_args = _build_request_args()
46
+
47
+ response = await client.request(**request_args)
48
+ raise_for_status(response)
49
+ return response.json()
@@ -7,7 +7,7 @@ from typing import Any
7
7
  import httpx
8
8
 
9
9
  from plato.chronos.errors import raise_for_status
10
- from plato.chronos.models import ChronosApiRegistryAgentListResponse
10
+ from plato.chronos.models import AgentListResponse
11
11
 
12
12
 
13
13
  def _build_request_args() -> dict[str, Any]:
@@ -22,23 +22,23 @@ def _build_request_args() -> dict[str, Any]:
22
22
 
23
23
  def sync(
24
24
  client: httpx.Client,
25
- ) -> ChronosApiRegistryAgentListResponse:
25
+ ) -> AgentListResponse:
26
26
  """List all agents from the registry with their ECR image URIs."""
27
27
 
28
28
  request_args = _build_request_args()
29
29
 
30
30
  response = client.request(**request_args)
31
31
  raise_for_status(response)
32
- return ChronosApiRegistryAgentListResponse.model_validate(response.json())
32
+ return AgentListResponse.model_validate(response.json())
33
33
 
34
34
 
35
35
  async def asyncio(
36
36
  client: httpx.AsyncClient,
37
- ) -> ChronosApiRegistryAgentListResponse:
37
+ ) -> AgentListResponse:
38
38
  """List all agents from the registry with their ECR image URIs."""
39
39
 
40
40
  request_args = _build_request_args()
41
41
 
42
42
  response = await client.request(**request_args)
43
43
  raise_for_status(response)
44
- return ChronosApiRegistryAgentListResponse.model_validate(response.json())
44
+ return AgentListResponse.model_validate(response.json())
@@ -1,11 +1,12 @@
1
1
  """API endpoints."""
2
2
 
3
- from . import create_runtime, delete_runtime, get_runtime, list_runtimes, test_runtime
3
+ from . import create_runtime, delete_runtime, get_runtime, get_runtime_logs, list_runtimes, test_runtime
4
4
 
5
5
  __all__ = [
6
6
  "list_runtimes",
7
7
  "create_runtime",
8
8
  "get_runtime",
9
9
  "delete_runtime",
10
+ "get_runtime_logs",
10
11
  "test_runtime",
11
12
  ]
@@ -0,0 +1,61 @@
1
+ """Get Runtime Logs"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+
11
+
12
+ def _build_request_args(
13
+ artifact_id: str,
14
+ x_api_key: str | None = None,
15
+ ) -> dict[str, Any]:
16
+ """Build request arguments."""
17
+ url = f"/api/runtimes/{artifact_id}/logs"
18
+
19
+ headers: dict[str, str] = {}
20
+ if x_api_key is not None:
21
+ headers["X-API-Key"] = x_api_key
22
+
23
+ return {
24
+ "method": "GET",
25
+ "url": url,
26
+ "headers": headers,
27
+ }
28
+
29
+
30
+ def sync(
31
+ client: httpx.Client,
32
+ artifact_id: str,
33
+ x_api_key: str | None = None,
34
+ ) -> dict[str, Any]:
35
+ """Get live build logs for a runtime by connecting to the VM."""
36
+
37
+ request_args = _build_request_args(
38
+ artifact_id=artifact_id,
39
+ x_api_key=x_api_key,
40
+ )
41
+
42
+ response = client.request(**request_args)
43
+ raise_for_status(response)
44
+ return response.json()
45
+
46
+
47
+ async def asyncio(
48
+ client: httpx.AsyncClient,
49
+ artifact_id: str,
50
+ x_api_key: str | None = None,
51
+ ) -> dict[str, Any]:
52
+ """Get live build logs for a runtime by connecting to the VM."""
53
+
54
+ request_args = _build_request_args(
55
+ artifact_id=artifact_id,
56
+ x_api_key=x_api_key,
57
+ )
58
+
59
+ response = await client.request(**request_args)
60
+ raise_for_status(response)
61
+ return response.json()
@@ -1,10 +1,33 @@
1
1
  """API endpoints."""
2
2
 
3
- from . import get_session, get_session_logs, get_session_logs_download, list_sessions
3
+ from . import (
4
+ close_session,
5
+ complete_session,
6
+ create_session,
7
+ get_session,
8
+ get_session_bash_logs_download,
9
+ get_session_envs,
10
+ get_session_live_logs,
11
+ get_session_logs,
12
+ get_session_logs_download,
13
+ get_session_status,
14
+ list_sessions,
15
+ list_tags,
16
+ update_session_tags,
17
+ )
4
18
 
5
19
  __all__ = [
6
20
  "list_sessions",
21
+ "create_session",
22
+ "list_tags",
7
23
  "get_session",
24
+ "get_session_status",
25
+ "update_session_tags",
26
+ "complete_session",
8
27
  "get_session_logs",
9
28
  "get_session_logs_download",
29
+ "get_session_bash_logs_download",
30
+ "get_session_envs",
31
+ "get_session_live_logs",
32
+ "close_session",
10
33
  ]
@@ -0,0 +1,66 @@
1
+ """Close Session"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import CloseSessionResponse
11
+
12
+
13
+ def _build_request_args(
14
+ public_id: str,
15
+ x_api_key: str | None = None,
16
+ ) -> dict[str, Any]:
17
+ """Build request arguments."""
18
+ url = f"/api/sessions/{public_id}/close"
19
+
20
+ headers: dict[str, str] = {}
21
+ if x_api_key is not None:
22
+ headers["X-API-Key"] = x_api_key
23
+
24
+ return {
25
+ "method": "POST",
26
+ "url": url,
27
+ "headers": headers,
28
+ }
29
+
30
+
31
+ def sync(
32
+ client: httpx.Client,
33
+ public_id: str,
34
+ x_api_key: str | None = None,
35
+ ) -> CloseSessionResponse:
36
+ """Close a running session.
37
+
38
+ Updates the session status to cancelled and closes the Plato session."""
39
+
40
+ request_args = _build_request_args(
41
+ public_id=public_id,
42
+ x_api_key=x_api_key,
43
+ )
44
+
45
+ response = client.request(**request_args)
46
+ raise_for_status(response)
47
+ return CloseSessionResponse.model_validate(response.json())
48
+
49
+
50
+ async def asyncio(
51
+ client: httpx.AsyncClient,
52
+ public_id: str,
53
+ x_api_key: str | None = None,
54
+ ) -> CloseSessionResponse:
55
+ """Close a running session.
56
+
57
+ Updates the session status to cancelled and closes the Plato session."""
58
+
59
+ request_args = _build_request_args(
60
+ public_id=public_id,
61
+ x_api_key=x_api_key,
62
+ )
63
+
64
+ response = await client.request(**request_args)
65
+ raise_for_status(response)
66
+ return CloseSessionResponse.model_validate(response.json())
@@ -0,0 +1,74 @@
1
+ """Complete Session"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from plato.chronos.errors import raise_for_status
10
+ from plato.chronos.models import CompleteSessionRequest, SessionResponse
11
+
12
+
13
+ def _build_request_args(
14
+ public_id: str,
15
+ body: CompleteSessionRequest,
16
+ x_api_key: str | None = None,
17
+ ) -> dict[str, Any]:
18
+ """Build request arguments."""
19
+ url = f"/api/sessions/{public_id}/complete"
20
+
21
+ headers: dict[str, str] = {}
22
+ if x_api_key is not None:
23
+ headers["X-API-Key"] = x_api_key
24
+
25
+ return {
26
+ "method": "POST",
27
+ "url": url,
28
+ "json": body.model_dump(mode="json", exclude_none=True),
29
+ "headers": headers,
30
+ }
31
+
32
+
33
+ def sync(
34
+ client: httpx.Client,
35
+ public_id: str,
36
+ body: CompleteSessionRequest,
37
+ x_api_key: str | None = None,
38
+ ) -> SessionResponse:
39
+ """Mark a session as completed or failed.
40
+
41
+ Called by the bootstrap script when the world runner finishes.
42
+ Uses API key auth (no org check) since it's called from the VM."""
43
+
44
+ request_args = _build_request_args(
45
+ public_id=public_id,
46
+ body=body,
47
+ x_api_key=x_api_key,
48
+ )
49
+
50
+ response = client.request(**request_args)
51
+ raise_for_status(response)
52
+ return SessionResponse.model_validate(response.json())
53
+
54
+
55
+ async def asyncio(
56
+ client: httpx.AsyncClient,
57
+ public_id: str,
58
+ body: CompleteSessionRequest,
59
+ x_api_key: str | None = None,
60
+ ) -> SessionResponse:
61
+ """Mark a session as completed or failed.
62
+
63
+ Called by the bootstrap script when the world runner finishes.
64
+ Uses API key auth (no org check) since it's called from the VM."""
65
+
66
+ request_args = _build_request_args(
67
+ public_id=public_id,
68
+ body=body,
69
+ x_api_key=x_api_key,
70
+ )
71
+
72
+ response = await client.request(**request_args)
73
+ raise_for_status(response)
74
+ return SessionResponse.model_validate(response.json())