asteroid-odyssey 1.3.11__py3-none-any.whl → 1.3.12__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.
- asteroid_odyssey/client.py +89 -187
- {asteroid_odyssey-1.3.11.dist-info → asteroid_odyssey-1.3.12.dist-info}/METADATA +1 -1
- {asteroid_odyssey-1.3.11.dist-info → asteroid_odyssey-1.3.12.dist-info}/RECORD +5 -5
- {asteroid_odyssey-1.3.11.dist-info → asteroid_odyssey-1.3.12.dist-info}/WHEEL +0 -0
- {asteroid_odyssey-1.3.11.dist-info → asteroid_odyssey-1.3.12.dist-info}/top_level.txt +0 -0
asteroid_odyssey/client.py
CHANGED
|
@@ -19,12 +19,7 @@ from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
|
|
19
19
|
from .agents_v1_gen import (
|
|
20
20
|
Configuration as AgentsV1Configuration,
|
|
21
21
|
ApiClient as AgentsV1ApiClient,
|
|
22
|
-
APIApi as AgentsV1APIApi,
|
|
23
|
-
ExecutionApi as AgentsV1ExecutionApi,
|
|
24
22
|
AgentProfileApi as AgentsV1AgentProfileApi,
|
|
25
|
-
ExecutionStatusResponse,
|
|
26
|
-
ExecutionResult,
|
|
27
|
-
Status,
|
|
28
23
|
CreateAgentProfileRequest,
|
|
29
24
|
UpdateAgentProfileRequest,
|
|
30
25
|
DeleteAgentProfile200Response,
|
|
@@ -49,6 +44,7 @@ from .agents_v2_gen import (
|
|
|
49
44
|
AgentsExecutionSortField as ExecutionSortField,
|
|
50
45
|
AgentsExecutionStatus as ExecutionStatus,
|
|
51
46
|
AgentsExecutionListItem as ExecutionListItem,
|
|
47
|
+
AgentsExecutionExecutionResult as ExecutionResult,
|
|
52
48
|
ExecutionsList200Response,
|
|
53
49
|
CommonSortDirection as SortDirection,
|
|
54
50
|
)
|
|
@@ -131,7 +127,7 @@ class AsteroidClient:
|
|
|
131
127
|
|
|
132
128
|
Args:
|
|
133
129
|
api_key: Your API key for authentication
|
|
134
|
-
base_url: Optional base URL (defaults to https://odyssey.asteroid.ai
|
|
130
|
+
base_url: Optional base URL (defaults to https://odyssey.asteroid.ai)
|
|
135
131
|
|
|
136
132
|
Example:
|
|
137
133
|
client = AsteroidClient('your-api-key')
|
|
@@ -139,23 +135,22 @@ class AsteroidClient:
|
|
|
139
135
|
if api_key is None:
|
|
140
136
|
raise TypeError("API key cannot be None")
|
|
141
137
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
base = base_url or "https://odyssey.asteroid.ai"
|
|
139
|
+
|
|
140
|
+
# Configure the V1 API client (used for agent profiles and credentials)
|
|
141
|
+
v1_config = AgentsV1Configuration(
|
|
142
|
+
host=f"{base}/api/v1",
|
|
145
143
|
api_key={'ApiKeyAuth': api_key}
|
|
146
144
|
)
|
|
147
|
-
|
|
148
|
-
self.api_client = AgentsV1ApiClient(config)
|
|
149
|
-
self.api_api = AgentsV1APIApi(self.api_client)
|
|
150
|
-
self.execution_api = AgentsV1ExecutionApi(self.api_client)
|
|
145
|
+
self.api_client = AgentsV1ApiClient(v1_config)
|
|
151
146
|
self.agent_profile_api = AgentsV1AgentProfileApi(self.api_client)
|
|
152
147
|
|
|
153
|
-
# Configure the V2 API client
|
|
154
|
-
|
|
155
|
-
host=
|
|
148
|
+
# Configure the V2 API client (used for agents, executions, files)
|
|
149
|
+
v2_config = AgentsV2Configuration(
|
|
150
|
+
host=f"{base}/agents/v2",
|
|
156
151
|
api_key={'ApiKeyAuth': api_key}
|
|
157
152
|
)
|
|
158
|
-
self.agents_v2_api_client = AgentsV2ApiClient(
|
|
153
|
+
self.agents_v2_api_client = AgentsV2ApiClient(v2_config)
|
|
159
154
|
self.agents_v2_agents_api = AgentsV2AgentsApi(self.agents_v2_api_client)
|
|
160
155
|
self.agents_v2_execution_api = AgentsV2ExecutionApi(self.agents_v2_api_client)
|
|
161
156
|
self.agents_v2_files_api = AgentsV2FilesApi(self.agents_v2_api_client)
|
|
@@ -205,65 +200,41 @@ class AsteroidClient:
|
|
|
205
200
|
except ApiException as e:
|
|
206
201
|
raise AsteroidAPIError(f"Failed to execute agent: {e}") from e
|
|
207
202
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def get_execution_status(self, execution_id: str) -> ExecutionStatusResponse:
|
|
203
|
+
def get_execution(self, execution_id: str) -> ExecutionListItem:
|
|
211
204
|
"""
|
|
212
|
-
Get
|
|
205
|
+
Get a single execution by ID with all details.
|
|
213
206
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Returns:
|
|
218
|
-
The execution status details
|
|
219
|
-
|
|
220
|
-
Raises:
|
|
221
|
-
AsteroidAPIError: If the status request fails
|
|
222
|
-
|
|
223
|
-
Example:
|
|
224
|
-
status = client.get_execution_status(execution_id)
|
|
225
|
-
print(status.status)
|
|
226
|
-
"""
|
|
227
|
-
try:
|
|
228
|
-
return self.execution_api.get_execution_status(execution_id)
|
|
229
|
-
except ApiException as e:
|
|
230
|
-
raise AsteroidAPIError(f"Failed to get execution status: {e}") from e
|
|
231
|
-
|
|
232
|
-
def get_execution_result(self, execution_id: str) -> ExecutionResult:
|
|
233
|
-
"""
|
|
234
|
-
Get the final result of an execution.
|
|
207
|
+
This method returns comprehensive execution information including status,
|
|
208
|
+
result, browser recording URL, and other metadata.
|
|
235
209
|
|
|
236
210
|
Args:
|
|
237
211
|
execution_id: The execution identifier
|
|
238
212
|
|
|
239
213
|
Returns:
|
|
240
|
-
The execution
|
|
214
|
+
The execution details including:
|
|
215
|
+
- status: Current execution status
|
|
216
|
+
- execution_result: Result with outcome and reasoning (if terminal)
|
|
217
|
+
- browser_recording_url: Recording URL (if browser session was used)
|
|
218
|
+
- browser_live_view_url: Live view URL (if execution is running)
|
|
219
|
+
- agent_id, agent_name, agent_version: Agent information
|
|
220
|
+
- created_at, terminal_at, duration: Timing information
|
|
221
|
+
- metadata, comments, human_labels: Additional data
|
|
241
222
|
|
|
242
223
|
Raises:
|
|
243
|
-
AsteroidAPIError: If the
|
|
224
|
+
AsteroidAPIError: If the request fails
|
|
244
225
|
|
|
245
226
|
Example:
|
|
246
|
-
|
|
247
|
-
print(
|
|
227
|
+
execution = client.get_execution(execution_id)
|
|
228
|
+
print(f"Status: {execution.status}")
|
|
229
|
+
if execution.execution_result:
|
|
230
|
+
print(f"Outcome: {execution.execution_result.outcome}")
|
|
231
|
+
if execution.browser_recording_url:
|
|
232
|
+
print(f"Recording: {execution.browser_recording_url}")
|
|
248
233
|
"""
|
|
249
234
|
try:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if response.error:
|
|
253
|
-
raise AsteroidAPIError(response.error)
|
|
254
|
-
|
|
255
|
-
# Handle case where execution_result might be None or have invalid data
|
|
256
|
-
if response.execution_result is None:
|
|
257
|
-
raise AsteroidAPIError("Execution result is not available yet")
|
|
258
|
-
|
|
259
|
-
return response.execution_result
|
|
235
|
+
return self.agents_v2_execution_api.execution_get(execution_id)
|
|
260
236
|
except ApiException as e:
|
|
261
|
-
raise AsteroidAPIError(f"Failed to get execution
|
|
262
|
-
except Exception as e:
|
|
263
|
-
# Handle validation errors from ExecutionResult model
|
|
264
|
-
if "must be one of enum values" in str(e):
|
|
265
|
-
raise AsteroidAPIError("Execution result is not available yet - execution may still be running") from e
|
|
266
|
-
raise e
|
|
237
|
+
raise AsteroidAPIError(f"Failed to get execution: {e}") from e
|
|
267
238
|
|
|
268
239
|
def wait_for_execution_result(
|
|
269
240
|
self,
|
|
@@ -274,7 +245,7 @@ class AsteroidClient:
|
|
|
274
245
|
"""
|
|
275
246
|
Wait for an execution to reach a terminal state and return the result.
|
|
276
247
|
|
|
277
|
-
Continuously polls the execution
|
|
248
|
+
Continuously polls the execution until it's either "completed",
|
|
278
249
|
"cancelled", or "failed".
|
|
279
250
|
|
|
280
251
|
Args:
|
|
@@ -306,31 +277,21 @@ class AsteroidClient:
|
|
|
306
277
|
if elapsed_time >= timeout:
|
|
307
278
|
raise TimeoutError(f"Execution {execution_id} timed out after {timeout}s")
|
|
308
279
|
|
|
309
|
-
|
|
310
|
-
current_status =
|
|
280
|
+
execution = self.get_execution(execution_id)
|
|
281
|
+
current_status = execution.status
|
|
311
282
|
|
|
312
|
-
if current_status ==
|
|
313
|
-
|
|
314
|
-
return
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
execution_result = self.get_execution_result(execution_id)
|
|
325
|
-
reason = f" - {status_response.reason}" if status_response.reason else ""
|
|
326
|
-
raise ExecutionError(
|
|
327
|
-
f"Execution {execution_id} ended with status: {current_status.value}{reason}",
|
|
328
|
-
execution_result
|
|
329
|
-
)
|
|
330
|
-
except Exception as e:
|
|
331
|
-
# If we can't get the execution result, fall back to the original behavior
|
|
332
|
-
reason = f" - {status_response.reason}" if status_response.reason else ""
|
|
333
|
-
raise ExecutionError(f"Execution {execution_id} ended with status: {current_status.value}{reason}") from e
|
|
283
|
+
if current_status == ExecutionStatus.COMPLETED:
|
|
284
|
+
if execution.execution_result:
|
|
285
|
+
return execution.execution_result
|
|
286
|
+
# Execution completed but result not ready yet, wait a bit more
|
|
287
|
+
time.sleep(interval)
|
|
288
|
+
continue
|
|
289
|
+
|
|
290
|
+
elif current_status in [ExecutionStatus.FAILED, ExecutionStatus.CANCELLED]:
|
|
291
|
+
raise ExecutionError(
|
|
292
|
+
f"Execution {execution_id} ended with status: {current_status.value}",
|
|
293
|
+
execution.execution_result
|
|
294
|
+
)
|
|
334
295
|
|
|
335
296
|
# Wait for the specified interval before polling again
|
|
336
297
|
time.sleep(interval)
|
|
@@ -411,28 +372,7 @@ class AsteroidClient:
|
|
|
411
372
|
except ApiException as e:
|
|
412
373
|
raise AsteroidAPIError(f"Failed to upload execution files: {e}") from e
|
|
413
374
|
|
|
414
|
-
|
|
415
|
-
"""
|
|
416
|
-
Get the browser session recording URL for a completed execution.
|
|
417
|
-
|
|
418
|
-
Args:
|
|
419
|
-
execution_id: The execution identifier
|
|
420
|
-
|
|
421
|
-
Returns:
|
|
422
|
-
The URL of the browser session recording
|
|
423
|
-
|
|
424
|
-
Raises:
|
|
425
|
-
Exception: If the recording request fails
|
|
426
|
-
|
|
427
|
-
Example:
|
|
428
|
-
recording_url = client.get_browser_session_recording(execution_id)
|
|
429
|
-
print(f"Recording available at: {recording_url}")
|
|
430
|
-
"""
|
|
431
|
-
try:
|
|
432
|
-
response = self.execution_api.get_browser_session_recording(execution_id)
|
|
433
|
-
return response.recording_url
|
|
434
|
-
except ApiException as e:
|
|
435
|
-
raise AsteroidAPIError(f"Failed to get browser session recording: {e}") from e
|
|
375
|
+
# --- V1 (Agent Profiles) ---
|
|
436
376
|
|
|
437
377
|
def get_agent_profiles(self, organization_id: str) -> List[AgentProfile]:
|
|
438
378
|
"""
|
|
@@ -686,47 +626,34 @@ class AsteroidClient:
|
|
|
686
626
|
if elapsed_time >= timeout:
|
|
687
627
|
raise TimeoutError(f"Wait for interaction on execution {execution_id} timed out after {timeout}s")
|
|
688
628
|
|
|
689
|
-
# Get current
|
|
690
|
-
|
|
691
|
-
current_status =
|
|
629
|
+
# Get current execution state
|
|
630
|
+
execution = self.get_execution(execution_id)
|
|
631
|
+
current_status = execution.status
|
|
692
632
|
status_str = current_status.value.lower()
|
|
693
633
|
|
|
694
634
|
# Handle terminal states
|
|
695
|
-
if current_status ==
|
|
696
|
-
|
|
697
|
-
execution_result = self.get_execution_result(execution_id)
|
|
635
|
+
if current_status == ExecutionStatus.COMPLETED:
|
|
636
|
+
if execution.execution_result:
|
|
698
637
|
return AgentInteractionResult(
|
|
699
638
|
is_terminal=True,
|
|
700
639
|
status=status_str,
|
|
701
640
|
agent_message=None,
|
|
702
|
-
execution_result=execution_result
|
|
641
|
+
execution_result=execution.execution_result
|
|
703
642
|
)
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
continue
|
|
708
|
-
raise e
|
|
643
|
+
# Execution completed but result not ready yet, wait a bit more
|
|
644
|
+
time.sleep(poll_interval)
|
|
645
|
+
continue
|
|
709
646
|
|
|
710
|
-
elif current_status in [
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
execution_result=execution_result
|
|
718
|
-
)
|
|
719
|
-
except AsteroidAPIError as e:
|
|
720
|
-
# If we can't get the execution result, still return terminal state
|
|
721
|
-
return AgentInteractionResult(
|
|
722
|
-
is_terminal=True,
|
|
723
|
-
status=status_str,
|
|
724
|
-
agent_message=None,
|
|
725
|
-
execution_result=None
|
|
726
|
-
)
|
|
647
|
+
elif current_status in [ExecutionStatus.FAILED, ExecutionStatus.CANCELLED]:
|
|
648
|
+
return AgentInteractionResult(
|
|
649
|
+
is_terminal=True,
|
|
650
|
+
status=status_str,
|
|
651
|
+
agent_message=None,
|
|
652
|
+
execution_result=execution.execution_result
|
|
653
|
+
)
|
|
727
654
|
|
|
728
655
|
# Handle agent interaction request
|
|
729
|
-
elif current_status ==
|
|
656
|
+
elif current_status == ExecutionStatus.PAUSED_BY_AGENT:
|
|
730
657
|
# Get the agent's message/request
|
|
731
658
|
agent_message = self._extract_agent_request_message(execution_id)
|
|
732
659
|
return AgentInteractionResult(
|
|
@@ -1191,47 +1118,39 @@ def execute_agent(
|
|
|
1191
1118
|
version,
|
|
1192
1119
|
)
|
|
1193
1120
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
def get_execution_status(client: AsteroidClient, execution_id: str) -> ExecutionStatusResponse:
|
|
1199
|
-
"""
|
|
1200
|
-
Get the current status for an execution.
|
|
1201
|
-
|
|
1202
|
-
Args:
|
|
1203
|
-
client: The AsteroidClient instance
|
|
1204
|
-
execution_id: The execution identifier
|
|
1205
|
-
|
|
1206
|
-
Returns:
|
|
1207
|
-
The execution status details
|
|
1208
|
-
|
|
1209
|
-
Example:
|
|
1210
|
-
status = get_execution_status(client, execution_id)
|
|
1211
|
-
print(status.status)
|
|
1121
|
+
def get_execution(client: AsteroidClient, execution_id: str) -> ExecutionListItem:
|
|
1212
1122
|
"""
|
|
1213
|
-
|
|
1214
|
-
|
|
1123
|
+
Get a single execution by ID with all details.
|
|
1215
1124
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
Get the final result of an execution.
|
|
1125
|
+
This function returns comprehensive execution information including status,
|
|
1126
|
+
result, browser recording URL, and other metadata.
|
|
1219
1127
|
|
|
1220
1128
|
Args:
|
|
1221
1129
|
client: The AsteroidClient instance
|
|
1222
1130
|
execution_id: The execution identifier
|
|
1223
1131
|
|
|
1224
1132
|
Returns:
|
|
1225
|
-
The execution
|
|
1133
|
+
The execution details including:
|
|
1134
|
+
- status: Current execution status
|
|
1135
|
+
- execution_result: Result with outcome and reasoning (if terminal)
|
|
1136
|
+
- browser_recording_url: Recording URL (if browser session was used)
|
|
1137
|
+
- browser_live_view_url: Live view URL (if execution is running)
|
|
1138
|
+
- agent_id, agent_name, agent_version: Agent information
|
|
1139
|
+
- created_at, terminal_at, duration: Timing information
|
|
1140
|
+
- metadata, comments, human_labels: Additional data
|
|
1226
1141
|
|
|
1227
1142
|
Raises:
|
|
1228
|
-
|
|
1143
|
+
AsteroidAPIError: If the request fails
|
|
1229
1144
|
|
|
1230
1145
|
Example:
|
|
1231
|
-
|
|
1232
|
-
print(
|
|
1146
|
+
execution = get_execution(client, execution_id)
|
|
1147
|
+
print(f"Status: {execution.status}")
|
|
1148
|
+
if execution.execution_result:
|
|
1149
|
+
print(f"Outcome: {execution.execution_result.outcome}")
|
|
1150
|
+
if execution.browser_recording_url:
|
|
1151
|
+
print(f"Recording: {execution.browser_recording_url}")
|
|
1233
1152
|
"""
|
|
1234
|
-
return client.
|
|
1153
|
+
return client.get_execution(execution_id)
|
|
1235
1154
|
|
|
1236
1155
|
|
|
1237
1156
|
def wait_for_execution_result(
|
|
@@ -1341,22 +1260,7 @@ def stage_temp_files(
|
|
|
1341
1260
|
return client.stage_temp_files(organization_id, files, default_filename)
|
|
1342
1261
|
|
|
1343
1262
|
|
|
1344
|
-
|
|
1345
|
-
"""
|
|
1346
|
-
Get the browser session recording URL for a completed execution.
|
|
1347
|
-
|
|
1348
|
-
Args:
|
|
1349
|
-
client: The AsteroidClient instance
|
|
1350
|
-
execution_id: The execution identifier
|
|
1351
|
-
|
|
1352
|
-
Returns:
|
|
1353
|
-
The URL of the browser session recording
|
|
1354
|
-
|
|
1355
|
-
Example:
|
|
1356
|
-
recording_url = get_browser_session_recording(client, execution_id)
|
|
1357
|
-
print(f"Recording available at: {recording_url}")
|
|
1358
|
-
"""
|
|
1359
|
-
return client.get_browser_session_recording(execution_id)
|
|
1263
|
+
# --- V1 (Agent Profiles) ---
|
|
1360
1264
|
|
|
1361
1265
|
def get_agent_profiles(client: AsteroidClient, organization_id: Optional[str] = None) -> List[AgentProfile]:
|
|
1362
1266
|
"""
|
|
@@ -1687,14 +1591,11 @@ __all__ = [
|
|
|
1687
1591
|
'create_client',
|
|
1688
1592
|
# Agent Execution (V2)
|
|
1689
1593
|
'execute_agent',
|
|
1594
|
+
'get_execution',
|
|
1690
1595
|
'get_executions',
|
|
1691
|
-
# Execution Status & Results (V1)
|
|
1692
|
-
'get_execution_status',
|
|
1693
|
-
'get_execution_result',
|
|
1694
1596
|
'wait_for_execution_result',
|
|
1695
1597
|
'upload_execution_files',
|
|
1696
1598
|
'stage_temp_files',
|
|
1697
|
-
'get_browser_session_recording',
|
|
1698
1599
|
# Agent Profiles (V1)
|
|
1699
1600
|
'get_agent_profiles',
|
|
1700
1601
|
'get_agent_profile',
|
|
@@ -1720,6 +1621,7 @@ __all__ = [
|
|
|
1720
1621
|
'TempFilesResponse',
|
|
1721
1622
|
'ExecuteAgentRequest',
|
|
1722
1623
|
'ExecutionListItem',
|
|
1624
|
+
'ExecutionResult',
|
|
1723
1625
|
'ExecutionsList200Response',
|
|
1724
1626
|
'ExecutionStatus',
|
|
1725
1627
|
'ExecutionSortField',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
asteroid_odyssey/__init__.py,sha256=po0AK2n1AiFyeAywL4Ju3qHGzTcRuH2LuXstuXthbT0,1273
|
|
2
|
-
asteroid_odyssey/client.py,sha256=
|
|
2
|
+
asteroid_odyssey/client.py,sha256=Xbx62w9l1syhdl8lnYUBNwLGOl8bN2mFGrGbk9RbtmA,63609
|
|
3
3
|
asteroid_odyssey/agents_v1_gen/__init__.py,sha256=8ULksHLOQJbxz9LkUs0sHFs47cWst2SeKs3NLGlLCjk,2841
|
|
4
4
|
asteroid_odyssey/agents_v1_gen/api_client.py,sha256=sxH4_y4LtJLTmK9Sd67qYIkHwnbjLGFI7aaL-Y4xZUs,27513
|
|
5
5
|
asteroid_odyssey/agents_v1_gen/api_response.py,sha256=eMxw1mpmJcoGZ3gs9z6jM4oYoZ10Gjk333s9sKxGv7s,652
|
|
@@ -128,7 +128,7 @@ asteroid_odyssey/agents_v2_gen/models/common_sort_direction.py,sha256=UBW99PM3QR
|
|
|
128
128
|
asteroid_odyssey/agents_v2_gen/models/common_unauthorized_error_body.py,sha256=Ng62vZVuPWEkTvdnYimbItSKhUGT9G52ZOapMQ2O7Xg,2897
|
|
129
129
|
asteroid_odyssey/agents_v2_gen/models/executions_list200_response.py,sha256=hmZBiOEUKpzEptDcElwgNwhCwSnXFJsrBbb9w2amGiM,3302
|
|
130
130
|
asteroid_odyssey/agents_v2_gen/models/version.py,sha256=Vjiri_a5CcDJ1lSziRqif5HuFpaxneVDLIB1r8SFIkE,707
|
|
131
|
-
asteroid_odyssey-1.3.
|
|
132
|
-
asteroid_odyssey-1.3.
|
|
133
|
-
asteroid_odyssey-1.3.
|
|
134
|
-
asteroid_odyssey-1.3.
|
|
131
|
+
asteroid_odyssey-1.3.12.dist-info/METADATA,sha256=ZGau6sWIHr0pggeik6aF6XBQPJqfv3m8pPQFyB3PgVA,7109
|
|
132
|
+
asteroid_odyssey-1.3.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
133
|
+
asteroid_odyssey-1.3.12.dist-info/top_level.txt,sha256=h4T6NKscnThJ4Nhzors2NKlJeZzepnM7XvDgsnfi5HA,17
|
|
134
|
+
asteroid_odyssey-1.3.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|