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.
- plato/__init__.py +0 -9
- 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 +99 -430
- plato/agents/base.py +145 -0
- plato/agents/build.py +61 -0
- plato/agents/config.py +160 -0
- plato/agents/logging.py +515 -0
- plato/agents/runner.py +191 -0
- plato/agents/trajectory.py +266 -0
- plato/chronos/models/__init__.py +1 -1
- plato/sims/cli.py +299 -123
- plato/sims/registry.py +77 -4
- plato/v1/cli/agent.py +88 -84
- plato/v1/cli/pm.py +84 -44
- plato/v1/cli/sandbox.py +241 -61
- plato/v1/cli/ssh.py +16 -4
- plato/v1/cli/verify.py +685 -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/__init__.py +2 -0
- plato/v2/async_/environment.py +31 -0
- plato/v2/async_/session.py +72 -4
- plato/v2/sync/environment.py +31 -0
- plato/v2/sync/session.py +72 -4
- plato/worlds/README.md +71 -56
- plato/worlds/__init__.py +56 -18
- plato/worlds/base.py +578 -93
- plato/worlds/config.py +276 -74
- plato/worlds/runner.py +475 -80
- {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/METADATA +3 -3
- {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/RECORD +41 -36
- {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/entry_points.txt +1 -0
- plato/agents/callback.py +0 -246
- plato/world/__init__.py +0 -44
- plato/world/base.py +0 -267
- plato/world/config.py +0 -139
- plato/world/types.py +0 -47
- {plato_sdk_v2-2.0.64.dist-info → plato_sdk_v2-2.3.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""ATIF (Agent Trajectory Interchange Format) models.
|
|
2
|
+
|
|
3
|
+
This module provides Pydantic models for the ATIF specification,
|
|
4
|
+
a standardized format for logging agent interaction history.
|
|
5
|
+
|
|
6
|
+
Matches Harbor's trajectory format exactly for compatibility.
|
|
7
|
+
Spec: https://harborframework.com/docs/trajectory-format
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
from typing import Any, Literal
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, Field
|
|
16
|
+
|
|
17
|
+
SCHEMA_VERSION: Literal["ATIF-v1.0", "ATIF-v1.1", "ATIF-v1.2", "ATIF-v1.3", "ATIF-v1.4", "ATIF-v1.5"] = "ATIF-v1.5"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Metrics(BaseModel):
|
|
21
|
+
"""LLM operational and confidence data."""
|
|
22
|
+
|
|
23
|
+
model_config = {"extra": "forbid"}
|
|
24
|
+
|
|
25
|
+
prompt_tokens: int | None = Field(default=None, description="Number of tokens in the prompt")
|
|
26
|
+
completion_tokens: int | None = Field(default=None, description="Number of tokens in the completion")
|
|
27
|
+
cached_tokens: int | None = Field(default=None, description="Number of cached tokens used")
|
|
28
|
+
cost_usd: float | None = Field(default=None, description="Cost in USD for this step")
|
|
29
|
+
prompt_token_ids: list[int] | None = Field(default=None, description="Token IDs for the prompt")
|
|
30
|
+
completion_token_ids: list[int] | None = Field(default=None, description="Token IDs for the completion")
|
|
31
|
+
logprobs: list[float] | None = Field(default=None, description="Log probabilities for completion tokens")
|
|
32
|
+
extra: dict[str, Any] | None = Field(default=None, description="Custom metrics")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FinalMetrics(BaseModel):
|
|
36
|
+
"""Trajectory-level aggregate statistics."""
|
|
37
|
+
|
|
38
|
+
model_config = {"extra": "forbid"}
|
|
39
|
+
|
|
40
|
+
total_prompt_tokens: int | None = Field(
|
|
41
|
+
default=None,
|
|
42
|
+
description="Sum of all prompt tokens across all steps, including cached tokens",
|
|
43
|
+
)
|
|
44
|
+
total_completion_tokens: int | None = Field(
|
|
45
|
+
default=None,
|
|
46
|
+
description="Sum of all completion tokens across all steps",
|
|
47
|
+
)
|
|
48
|
+
total_cached_tokens: int | None = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="Sum of all cached tokens across all steps",
|
|
51
|
+
)
|
|
52
|
+
total_cost_usd: float | None = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description="Total real monetary cost for the entire trajectory",
|
|
55
|
+
)
|
|
56
|
+
total_steps: int | None = Field(
|
|
57
|
+
default=None,
|
|
58
|
+
ge=0,
|
|
59
|
+
description="Number of steps in the trajectory",
|
|
60
|
+
)
|
|
61
|
+
extra: dict[str, Any] | None = Field(default=None, description="Custom aggregate metrics")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ToolCall(BaseModel):
|
|
65
|
+
"""A function/tool invocation."""
|
|
66
|
+
|
|
67
|
+
model_config = {"extra": "forbid"}
|
|
68
|
+
|
|
69
|
+
tool_call_id: str = Field(..., description="Unique identifier for this specific tool call")
|
|
70
|
+
function_name: str = Field(..., description="The name of the function or tool being invoked")
|
|
71
|
+
arguments: dict[str, Any] = Field(..., description="Arguments passed to the function (can be empty dict)")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ObservationResult(BaseModel):
|
|
75
|
+
"""Result from a single tool call."""
|
|
76
|
+
|
|
77
|
+
model_config = {"extra": "forbid"}
|
|
78
|
+
|
|
79
|
+
source_call_id: str = Field(..., description="ID of the tool call that produced this result")
|
|
80
|
+
content: str = Field(..., description="The result content from the tool execution")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class Observation(BaseModel):
|
|
84
|
+
"""Environment feedback from tool execution."""
|
|
85
|
+
|
|
86
|
+
model_config = {"extra": "forbid"}
|
|
87
|
+
|
|
88
|
+
results: list[ObservationResult] = Field(..., description="Results from tool executions")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class Step(BaseModel):
|
|
92
|
+
"""A single interaction step in the trajectory."""
|
|
93
|
+
|
|
94
|
+
model_config = {"extra": "forbid"}
|
|
95
|
+
|
|
96
|
+
step_id: int = Field(..., ge=1, description="Ordinal index of the turn (starting from 1)")
|
|
97
|
+
timestamp: str | None = Field(default=None, description="ISO 8601 timestamp")
|
|
98
|
+
source: Literal["user", "agent", "system"] = Field(..., description="Step originator")
|
|
99
|
+
message: str = Field(..., description="Dialogue content (allows empty string)")
|
|
100
|
+
|
|
101
|
+
# Agent-only fields
|
|
102
|
+
model_name: str | None = Field(default=None, description="LLM model used for this step")
|
|
103
|
+
reasoning_effort: str | float | None = Field(default=None, description="Effort measurement")
|
|
104
|
+
reasoning_content: str | None = Field(default=None, description="Agent's internal reasoning")
|
|
105
|
+
tool_calls: list[ToolCall] | None = Field(default=None, description="Structured action objects")
|
|
106
|
+
observation: Observation | None = Field(default=None, description="Environment feedback")
|
|
107
|
+
metrics: Metrics | None = Field(default=None, description="LLM operational and confidence data")
|
|
108
|
+
is_copied_context: bool | None = Field(default=None, description="Context reuse indicator (ATIF-v1.5+)")
|
|
109
|
+
|
|
110
|
+
# Custom metadata
|
|
111
|
+
extra: dict[str, Any] | None = Field(default=None, description="Custom metadata")
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
def user(cls, step_id: int, message: str, **kwargs: Any) -> Step:
|
|
115
|
+
"""Create a user step."""
|
|
116
|
+
return cls(
|
|
117
|
+
step_id=step_id,
|
|
118
|
+
timestamp=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
119
|
+
source="user",
|
|
120
|
+
message=message,
|
|
121
|
+
**kwargs,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
@classmethod
|
|
125
|
+
def agent(
|
|
126
|
+
cls,
|
|
127
|
+
step_id: int,
|
|
128
|
+
message: str,
|
|
129
|
+
model_name: str,
|
|
130
|
+
tool_calls: list[ToolCall] | None = None,
|
|
131
|
+
observation: Observation | None = None,
|
|
132
|
+
metrics: Metrics | None = None,
|
|
133
|
+
reasoning_content: str | None = None,
|
|
134
|
+
**kwargs: Any,
|
|
135
|
+
) -> Step:
|
|
136
|
+
"""Create an agent step."""
|
|
137
|
+
return cls(
|
|
138
|
+
step_id=step_id,
|
|
139
|
+
timestamp=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
140
|
+
source="agent",
|
|
141
|
+
message=message,
|
|
142
|
+
model_name=model_name,
|
|
143
|
+
tool_calls=tool_calls,
|
|
144
|
+
observation=observation,
|
|
145
|
+
metrics=metrics,
|
|
146
|
+
reasoning_content=reasoning_content,
|
|
147
|
+
**kwargs,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def system(cls, step_id: int, message: str, **kwargs: Any) -> Step:
|
|
152
|
+
"""Create a system step."""
|
|
153
|
+
return cls(
|
|
154
|
+
step_id=step_id,
|
|
155
|
+
timestamp=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
156
|
+
source="system",
|
|
157
|
+
message=message,
|
|
158
|
+
**kwargs,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class Agent(BaseModel):
|
|
163
|
+
"""Agent metadata."""
|
|
164
|
+
|
|
165
|
+
model_config = {"extra": "forbid"}
|
|
166
|
+
|
|
167
|
+
name: str = Field(..., description="The name of the agent system")
|
|
168
|
+
version: str = Field(..., description="The version identifier of the agent system")
|
|
169
|
+
model_name: str | None = Field(default=None, description="Default LLM model used for this trajectory")
|
|
170
|
+
tool_definitions: list[dict[str, Any]] | None = Field(
|
|
171
|
+
default=None,
|
|
172
|
+
description="Array of tool/function definitions available to the agent",
|
|
173
|
+
)
|
|
174
|
+
extra: dict[str, Any] | None = Field(default=None, description="Custom agent configuration details")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class Trajectory(BaseModel):
|
|
178
|
+
"""ATIF trajectory - the complete interaction history.
|
|
179
|
+
|
|
180
|
+
Example:
|
|
181
|
+
trajectory = Trajectory(
|
|
182
|
+
session_id="abc-123",
|
|
183
|
+
agent=Agent(name="openhands", version="0.37.0", model_name="claude-sonnet-4"),
|
|
184
|
+
steps=[
|
|
185
|
+
Step.user(1, "Fix the bug in main.py"),
|
|
186
|
+
Step.agent(2, "I'll analyze the code...", model_name="claude-sonnet-4"),
|
|
187
|
+
],
|
|
188
|
+
)
|
|
189
|
+
trajectory.to_file("/logs/agent/trajectory.json")
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
model_config = {"extra": "forbid"}
|
|
193
|
+
|
|
194
|
+
schema_version: Literal["ATIF-v1.0", "ATIF-v1.1", "ATIF-v1.2", "ATIF-v1.3", "ATIF-v1.4", "ATIF-v1.5"] = Field(
|
|
195
|
+
default="ATIF-v1.5",
|
|
196
|
+
description="String defining ATIF compatibility",
|
|
197
|
+
)
|
|
198
|
+
session_id: str = Field(..., description="Unique identifier for the entire agent run")
|
|
199
|
+
agent: Agent = Field(..., description="Object specifying the agent configuration")
|
|
200
|
+
steps: list[Step] = Field(
|
|
201
|
+
..., min_length=1, description="Array of step objects representing the complete interaction history"
|
|
202
|
+
)
|
|
203
|
+
notes: str | None = Field(default=None, description="Custom information, design notes, or explanations")
|
|
204
|
+
final_metrics: FinalMetrics | None = Field(default=None, description="Summary metrics for the entire trajectory")
|
|
205
|
+
continued_trajectory_ref: str | None = Field(
|
|
206
|
+
default=None,
|
|
207
|
+
description="Reference to continuation trajectory file if this trajectory is continued elsewhere",
|
|
208
|
+
)
|
|
209
|
+
extra: dict[str, Any] | None = Field(default=None, description="Custom root-level metadata")
|
|
210
|
+
|
|
211
|
+
def add_step(self, step: Step) -> None:
|
|
212
|
+
"""Add a step to the trajectory."""
|
|
213
|
+
self.steps.append(step)
|
|
214
|
+
|
|
215
|
+
def compute_final_metrics(self) -> FinalMetrics:
|
|
216
|
+
"""Compute aggregate metrics from all steps."""
|
|
217
|
+
total_prompt = 0
|
|
218
|
+
total_completion = 0
|
|
219
|
+
total_cached = 0
|
|
220
|
+
total_cost = 0.0
|
|
221
|
+
|
|
222
|
+
for step in self.steps:
|
|
223
|
+
if step.metrics:
|
|
224
|
+
if step.metrics.prompt_tokens:
|
|
225
|
+
total_prompt += step.metrics.prompt_tokens
|
|
226
|
+
if step.metrics.completion_tokens:
|
|
227
|
+
total_completion += step.metrics.completion_tokens
|
|
228
|
+
if step.metrics.cached_tokens:
|
|
229
|
+
total_cached += step.metrics.cached_tokens
|
|
230
|
+
if step.metrics.cost_usd:
|
|
231
|
+
total_cost += step.metrics.cost_usd
|
|
232
|
+
|
|
233
|
+
self.final_metrics = FinalMetrics(
|
|
234
|
+
total_prompt_tokens=total_prompt if total_prompt > 0 else None,
|
|
235
|
+
total_completion_tokens=total_completion if total_completion > 0 else None,
|
|
236
|
+
total_steps=len(self.steps),
|
|
237
|
+
total_cached_tokens=total_cached if total_cached > 0 else None,
|
|
238
|
+
total_cost_usd=total_cost if total_cost > 0 else None,
|
|
239
|
+
)
|
|
240
|
+
return self.final_metrics
|
|
241
|
+
|
|
242
|
+
def to_dict(self, exclude_none: bool = True) -> dict[str, Any]:
|
|
243
|
+
"""Convert to dictionary, optionally excluding None values."""
|
|
244
|
+
return self.model_dump(exclude_none=exclude_none)
|
|
245
|
+
|
|
246
|
+
def to_json(self, indent: int = 2) -> str:
|
|
247
|
+
"""Convert to JSON string."""
|
|
248
|
+
return self.model_dump_json(indent=indent, exclude_none=True)
|
|
249
|
+
|
|
250
|
+
def to_file(self, path: str) -> None:
|
|
251
|
+
"""Write trajectory to a JSON file."""
|
|
252
|
+
import json
|
|
253
|
+
from pathlib import Path as PathLib
|
|
254
|
+
|
|
255
|
+
PathLib(path).parent.mkdir(parents=True, exist_ok=True)
|
|
256
|
+
with open(path, "w") as f:
|
|
257
|
+
json.dump(self.to_dict(), f, indent=2)
|
|
258
|
+
|
|
259
|
+
@classmethod
|
|
260
|
+
def from_file(cls, path: str) -> Trajectory:
|
|
261
|
+
"""Load trajectory from a JSON file."""
|
|
262
|
+
import json
|
|
263
|
+
|
|
264
|
+
with open(path) as f:
|
|
265
|
+
data = json.load(f)
|
|
266
|
+
return cls(**data)
|