asteroid-odyssey 1.3.13__py3-none-any.whl → 1.6.0__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 (149) hide show
  1. asteroid_odyssey/__init__.py +254 -82
  2. asteroid_odyssey/api/__init__.py +8 -0
  3. asteroid_odyssey/{agents_v1_gen/api/agent_profile_api.py → api/agent_profiles_api.py} +414 -281
  4. asteroid_odyssey/{agents_v2_gen/api → api}/agents_api.py +30 -30
  5. asteroid_odyssey/{agents_v2_gen/api → api}/execution_api.py +32 -49
  6. asteroid_odyssey/{agents_v2_gen/api → api}/files_api.py +5 -5
  7. asteroid_odyssey/{agents_v2_gen/api_client.py → api_client.py} +10 -6
  8. asteroid_odyssey/{agents_v2_gen/configuration.py → configuration.py} +11 -4
  9. asteroid_odyssey/models/__init__.py +118 -0
  10. asteroid_odyssey/{agents_v2_gen/models → models}/agent_list200_response.py +1 -1
  11. asteroid_odyssey/models/agent_profile_clear_browser_cache200_response.py +87 -0
  12. asteroid_odyssey/models/agent_profiles_list200_response.py +101 -0
  13. asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_base.py +3 -3
  14. asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_execute_agent_request.py +7 -5
  15. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity.py +4 -4
  16. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_completed_info.py +65 -37
  17. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_completed_payload.py +8 -8
  18. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_failed_payload.py +9 -9
  19. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_started_info.py +50 -22
  20. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_started_payload.py +10 -10
  21. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_file_added_payload.py +6 -6
  22. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_payload_union.py +14 -14
  23. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_playwright_script_generated_payload.py +9 -9
  24. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_status_changed_payload.py +19 -19
  25. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_transitioned_node_payload.py +6 -6
  26. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_workflow_updated_payload.py +1 -1
  27. asteroid_odyssey/models/agents_execution_agent_query_context_completed_details.py +98 -0
  28. asteroid_odyssey/models/agents_execution_agent_query_context_started_details.py +96 -0
  29. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_cancelled_payload.py +1 -1
  30. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_comment.py +10 -10
  31. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_completed_payload.py +4 -4
  32. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_execution_result.py +6 -6
  33. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_ext_api_call_completed_details.py +6 -6
  34. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_failed_payload.py +5 -5
  35. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_file_read_completed_details.py +3 -3
  36. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_human_label.py +7 -7
  37. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_list_item.py +33 -37
  38. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_llm_call_started_details.py +1 -1
  39. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_obs_snapshot_with_selectors_completed_details.py +4 -4
  40. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_write_completed_details.py +7 -7
  41. asteroid_odyssey/models/agents_execution_script_eval_completed_details.py +101 -0
  42. asteroid_odyssey/models/agents_execution_script_eval_started_details.py +100 -0
  43. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_hybrid_playwright_completed_details.py +6 -6
  44. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_pad_run_function_completed_details.py +6 -6
  45. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_playwright_completed_details.py +6 -6
  46. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_read_started_details.py +4 -4
  47. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_run_function_started_details.py +4 -4
  48. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_search_replace_completed_details.py +5 -5
  49. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_search_replace_started_details.py +4 -4
  50. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_write_completed_details.py +4 -4
  51. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_terminal_payload.py +4 -4
  52. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_util_get_datetime_completed_details.py +4 -4
  53. asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_workflow_update.py +13 -13
  54. asteroid_odyssey/{agents_v2_gen/models → models}/agents_files_file.py +11 -11
  55. asteroid_odyssey/{agents_v2_gen/models → models}/agents_files_temp_files_response.py +1 -1
  56. asteroid_odyssey/{agents_v2_gen/models → models}/agents_graph_models_nodes_properties_playwright_script_llm_var.py +5 -5
  57. asteroid_odyssey/{agents_v1_gen/models/agent_profile.py → models/agents_profile_agent_profile.py} +37 -32
  58. asteroid_odyssey/{agents_v1_gen/models/cookie.py → models/agents_profile_cookie.py} +21 -26
  59. asteroid_odyssey/{agents_v1_gen/models/country_code.py → models/agents_profile_country_code.py} +5 -5
  60. asteroid_odyssey/{agents_v1_gen/models/create_agent_profile_request.py → models/agents_profile_create_agent_profile_request.py} +33 -28
  61. asteroid_odyssey/{agents_v1_gen/models/credential.py → models/agents_profile_credential.py} +13 -13
  62. asteroid_odyssey/models/agents_profile_operating_system.py +37 -0
  63. asteroid_odyssey/models/agents_profile_proxy_type.py +38 -0
  64. asteroid_odyssey/models/agents_profile_same_site.py +38 -0
  65. asteroid_odyssey/models/agents_profile_sort_field.py +38 -0
  66. asteroid_odyssey/models/agents_profile_update_agent_profile_request.py +129 -0
  67. asteroid_odyssey/{agents_v2_gen/models → models}/executions_list200_response.py +1 -1
  68. asteroid_odyssey/{agents_v2_gen/rest.py → rest.py} +2 -1
  69. asteroid_odyssey-1.6.0.dist-info/METADATA +65 -0
  70. asteroid_odyssey-1.6.0.dist-info/RECORD +119 -0
  71. asteroid_odyssey/agents_v1_gen/__init__.py +0 -53
  72. asteroid_odyssey/agents_v1_gen/api/__init__.py +0 -7
  73. asteroid_odyssey/agents_v1_gen/api/api_api.py +0 -516
  74. asteroid_odyssey/agents_v1_gen/api/execution_api.py +0 -1449
  75. asteroid_odyssey/agents_v1_gen/api_client.py +0 -797
  76. asteroid_odyssey/agents_v1_gen/configuration.py +0 -599
  77. asteroid_odyssey/agents_v1_gen/exceptions.py +0 -216
  78. asteroid_odyssey/agents_v1_gen/models/__init__.py +0 -34
  79. asteroid_odyssey/agents_v1_gen/models/browser_session_recording_response.py +0 -87
  80. asteroid_odyssey/agents_v1_gen/models/delete_agent_profile200_response.py +0 -87
  81. asteroid_odyssey/agents_v1_gen/models/error_response.py +0 -87
  82. asteroid_odyssey/agents_v1_gen/models/execution_response.py +0 -87
  83. asteroid_odyssey/agents_v1_gen/models/execution_result.py +0 -101
  84. asteroid_odyssey/agents_v1_gen/models/execution_result_response.py +0 -100
  85. asteroid_odyssey/agents_v1_gen/models/execution_status_response.py +0 -95
  86. asteroid_odyssey/agents_v1_gen/models/health_check200_response.py +0 -87
  87. asteroid_odyssey/agents_v1_gen/models/health_check500_response.py +0 -87
  88. asteroid_odyssey/agents_v1_gen/models/proxy_type.py +0 -38
  89. asteroid_odyssey/agents_v1_gen/models/status.py +0 -43
  90. asteroid_odyssey/agents_v1_gen/models/structured_agent_execution_request.py +0 -89
  91. asteroid_odyssey/agents_v1_gen/models/update_agent_profile_request.py +0 -126
  92. asteroid_odyssey/agents_v1_gen/rest.py +0 -257
  93. asteroid_odyssey/agents_v2_gen/__init__.py +0 -121
  94. asteroid_odyssey/agents_v2_gen/api/__init__.py +0 -7
  95. asteroid_odyssey/agents_v2_gen/api_response.py +0 -21
  96. asteroid_odyssey/agents_v2_gen/models/__init__.py +0 -102
  97. asteroid_odyssey/agents_v2_gen/py.typed +0 -0
  98. asteroid_odyssey/client.py +0 -1629
  99. asteroid_odyssey-1.3.13.dist-info/METADATA +0 -214
  100. asteroid_odyssey-1.3.13.dist-info/RECORD +0 -134
  101. /asteroid_odyssey/{agents_v1_gen/api_response.py → api_response.py} +0 -0
  102. /asteroid_odyssey/{agents_v2_gen/exceptions.py → exceptions.py} +0 -0
  103. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_execute_agent_response.py +0 -0
  104. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_sort_field.py +0 -0
  105. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_action_name.py +0 -0
  106. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_generic_payload.py +0 -0
  107. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_reasoning_payload.py +0 -0
  108. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_step_completed_payload.py +0 -0
  109. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_step_started_payload.py +0 -0
  110. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_user_message_received_payload.py +0 -0
  111. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_awaiting_confirmation_payload.py +0 -0
  112. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_cancel_reason.py +0 -0
  113. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_element_file_upload_completed_details.py +0 -0
  114. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_ext_get_mail_completed_details.py +0 -0
  115. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_file_list_completed_details.py +0 -0
  116. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_file_stage_completed_details.py +0 -0
  117. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_llm_call_purpose.py +0 -0
  118. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_nav_to_completed_details.py +0 -0
  119. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_nav_to_started_details.py +0 -0
  120. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_node_details.py +0 -0
  121. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_paused_payload.py +0 -0
  122. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_rules_details.py +0 -0
  123. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_read_completed_details.py +0 -0
  124. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_read_started_details.py +0 -0
  125. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_write_started_details.py +0 -0
  126. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_hybrid_playwright_started_details.py +0 -0
  127. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_playwright_started_details.py +0 -0
  128. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_read_completed_details.py +0 -0
  129. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_sort_field.py +0 -0
  130. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_status.py +0 -0
  131. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_transition_details.py +0 -0
  132. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_update_type.py +0 -0
  133. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_user_messages_add_text_body.py +0 -0
  134. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_util_get_datetime_started_details.py +0 -0
  135. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_files_temp_file.py +0 -0
  136. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_graph_models_nodes_properties_playwright_script_llm_var_type.py +0 -0
  137. /asteroid_odyssey/{agents_v2_gen/models → models}/agents_graph_models_transitions_transition_type.py +0 -0
  138. /asteroid_odyssey/{agents_v2_gen/models → models}/common_bad_request_error_body.py +0 -0
  139. /asteroid_odyssey/{agents_v2_gen/models → models}/common_error.py +0 -0
  140. /asteroid_odyssey/{agents_v2_gen/models → models}/common_forbidden_error_body.py +0 -0
  141. /asteroid_odyssey/{agents_v2_gen/models → models}/common_internal_server_error_body.py +0 -0
  142. /asteroid_odyssey/{agents_v2_gen/models → models}/common_not_found_error_body.py +0 -0
  143. /asteroid_odyssey/{agents_v2_gen/models → models}/common_os_error.py +0 -0
  144. /asteroid_odyssey/{agents_v2_gen/models → models}/common_sort_direction.py +0 -0
  145. /asteroid_odyssey/{agents_v2_gen/models → models}/common_unauthorized_error_body.py +0 -0
  146. /asteroid_odyssey/{agents_v2_gen/models → models}/version.py +0 -0
  147. /asteroid_odyssey/{agents_v1_gen/py.typed → py.typed} +0 -0
  148. {asteroid_odyssey-1.3.13.dist-info → asteroid_odyssey-1.6.0.dist-info}/WHEEL +0 -0
  149. {asteroid_odyssey-1.3.13.dist-info → asteroid_odyssey-1.6.0.dist-info}/top_level.txt +0 -0
@@ -1,1629 +0,0 @@
1
- """
2
- Asteroid Agents Python SDK - High-Level Client Interface
3
-
4
- Provides a clean, easy-to-use interface for interacting with the Asteroid Agents API,
5
- similar to the TypeScript SDK.
6
-
7
- This module provides a high-level client that wraps the generated OpenAPI client
8
- without modifying any generated files.
9
- """
10
-
11
- import time
12
- import os
13
- import base64
14
- import requests
15
- from pathlib import Path
16
- from typing import Dict, Any, Optional, List, Union, Tuple, NamedTuple
17
- from cryptography.hazmat.primitives import serialization
18
- from cryptography.hazmat.primitives.asymmetric import padding, rsa
19
- from .agents_v1_gen import (
20
- Configuration as AgentsV1Configuration,
21
- ApiClient as AgentsV1ApiClient,
22
- AgentProfileApi as AgentsV1AgentProfileApi,
23
- CreateAgentProfileRequest,
24
- UpdateAgentProfileRequest,
25
- DeleteAgentProfile200Response,
26
- AgentProfile,
27
- Credential,
28
- )
29
- from .agents_v1_gen.exceptions import ApiException
30
- from .agents_v2_gen import (
31
- AgentsAgentBase as Agent,
32
- AgentList200Response as AgentList200Response,
33
- Configuration as AgentsV2Configuration,
34
- ApiClient as AgentsV2ApiClient,
35
- AgentsApi as AgentsV2AgentsApi,
36
- ExecutionApi as AgentsV2ExecutionApi,
37
- FilesApi as AgentsV2FilesApi,
38
- AgentsExecutionActivity as ExecutionActivity,
39
- AgentsExecutionUserMessagesAddTextBody as ExecutionUserMessagesAddTextBody,
40
- AgentsFilesFile as File,
41
- AgentsAgentExecuteAgentRequest as ExecuteAgentRequest,
42
- AgentsFilesTempFile as TempFile,
43
- AgentsFilesTempFilesResponse as TempFilesResponse,
44
- AgentsExecutionSortField as ExecutionSortField,
45
- AgentsExecutionStatus as ExecutionStatus,
46
- AgentsExecutionListItem as ExecutionListItem,
47
- AgentsExecutionExecutionResult as ExecutionResult,
48
- ExecutionsList200Response,
49
- CommonSortDirection as SortDirection,
50
- )
51
-
52
-
53
- class AsteroidAPIError(Exception):
54
- """Base exception for all Asteroid API related errors."""
55
- pass
56
-
57
-
58
- class ExecutionError(AsteroidAPIError):
59
- """Raised when an execution fails or is cancelled."""
60
- def __init__(self, message: str, execution_result: Optional[ExecutionResult] = None):
61
- super().__init__(message)
62
- self.execution_result = execution_result
63
-
64
-
65
- class TimeoutError(AsteroidAPIError):
66
- """Raised when an execution times out."""
67
- def __init__(self, message: str):
68
- super().__init__(message)
69
-
70
-
71
- class AgentInteractionResult(NamedTuple):
72
- """Result returned by wait_for_agent_interaction method."""
73
- is_terminal: bool # True if execution reached a terminal state
74
- status: str # Current execution status
75
- agent_message: Optional[str] # Agent's message if requesting interaction
76
- execution_result: Optional[ExecutionResult] # Final result if terminal
77
-
78
-
79
- def encrypt_with_public_key(plaintext: str, pem_public_key: str) -> str:
80
- """
81
- Encrypt plaintext using RSA public key with PKCS1v15 padding.
82
-
83
- Args:
84
- plaintext: The string to encrypt
85
- pem_public_key: PEM-formatted RSA public key
86
-
87
- Returns:
88
- Base64-encoded encrypted string
89
-
90
- Raises:
91
- ValueError: If encryption fails or key is invalid
92
-
93
- Example:
94
- encrypted = encrypt_with_public_key("my_password", public_key_pem)
95
- """
96
- try:
97
- # Load the PEM public key (matches node-forge behavior)
98
- public_key = serialization.load_pem_public_key(pem_public_key.encode('utf-8'))
99
-
100
- if not isinstance(public_key, rsa.RSAPublicKey):
101
- raise ValueError("Invalid RSA public key")
102
-
103
- # Encrypt using PKCS1v15 padding (matches "RSAES-PKCS1-V1_5" from TypeScript)
104
- encrypted_bytes = public_key.encrypt(
105
- plaintext.encode('utf-8'),
106
- padding.PKCS1v15()
107
- )
108
-
109
- # Encode as base64 (matches forge.util.encode64)
110
- return base64.b64encode(encrypted_bytes).decode('utf-8')
111
-
112
- except Exception as e:
113
- raise ValueError(f"Failed to encrypt: {str(e)}") from e
114
-
115
-
116
- class AsteroidClient:
117
- """
118
- High-level client for the Asteroid Agents API.
119
-
120
- This class provides a convenient interface for executing agents and managing
121
- their execution lifecycle, similar to the TypeScript SDK.
122
- """
123
-
124
- def __init__(self, api_key: str, base_url: Optional[str] = None):
125
- """
126
- Create an API client with the provided API key.
127
-
128
- Args:
129
- api_key: Your API key for authentication
130
- base_url: Optional base URL (defaults to https://odyssey.asteroid.ai)
131
-
132
- Example:
133
- client = AsteroidClient('your-api-key')
134
- """
135
- if api_key is None:
136
- raise TypeError("API key cannot be None")
137
-
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",
143
- api_key={'ApiKeyAuth': api_key}
144
- )
145
- self.api_client = AgentsV1ApiClient(v1_config)
146
- self.agent_profile_api = AgentsV1AgentProfileApi(self.api_client)
147
-
148
- # Configure the V2 API client (used for agents, executions, files)
149
- v2_config = AgentsV2Configuration(
150
- host=f"{base}/agents/v2",
151
- api_key={'ApiKeyAuth': api_key}
152
- )
153
- self.agents_v2_api_client = AgentsV2ApiClient(v2_config)
154
- self.agents_v2_agents_api = AgentsV2AgentsApi(self.agents_v2_api_client)
155
- self.agents_v2_execution_api = AgentsV2ExecutionApi(self.agents_v2_api_client)
156
- self.agents_v2_files_api = AgentsV2FilesApi(self.agents_v2_api_client)
157
-
158
- # --- V2 ---
159
-
160
- def execute_agent(
161
- self,
162
- agent_id: str,
163
- dynamic_data: Optional[Dict[str, Any]] = None,
164
- agent_profile_id: Optional[str] = None,
165
- metadata: Optional[Dict[str, Any]] = None,
166
- temp_files: Optional[List[TempFile]] = None,
167
- version: Optional[int] = None,
168
- ) -> str:
169
- """
170
- Execute an agent with the provided parameters.
171
-
172
- Args:
173
- agent_id: The ID of the agent to execute
174
- dynamic_data: Dynamic data to be merged into the placeholders defined in prompts
175
- agent_profile_id: Optional ID of the agent profile to use
176
- metadata: Optional metadata key-value pairs for organizing and filtering executions
177
- temp_files: Optional list of temporary files to attach (must be pre-uploaded using stage_temp_files)
178
- version: Optional version of the agent to execute. If not provided, the latest version will be used.
179
-
180
- Returns:
181
- The execution ID
182
-
183
- Raises:
184
- AsteroidAPIError: If the execution request fails
185
-
186
- Example:
187
- execution_id = client.execute_agent('my-agent-id', {'input': 'some dynamic value'})
188
- execution_id = client.execute_agent('my-agent-id', {'input': 'value'}, version=3)
189
- """
190
- req = ExecuteAgentRequest(
191
- dynamic_data=dynamic_data,
192
- agent_profile_id=agent_profile_id,
193
- metadata=metadata,
194
- temp_files=temp_files,
195
- version=version,
196
- )
197
- try:
198
- response = self.agents_v2_agents_api.agent_execute_post(agent_id, req)
199
- return response.execution_id
200
- except ApiException as e:
201
- raise AsteroidAPIError(f"Failed to execute agent: {e}") from e
202
-
203
- def get_execution(self, execution_id: str) -> ExecutionListItem:
204
- """
205
- Get a single execution by ID with all details.
206
-
207
- This method returns comprehensive execution information including status,
208
- result, browser recording URL, and other metadata.
209
-
210
- Args:
211
- execution_id: The execution identifier
212
-
213
- Returns:
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
222
-
223
- Raises:
224
- AsteroidAPIError: If the request fails
225
-
226
- Example:
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}")
233
- """
234
- try:
235
- return self.agents_v2_execution_api.execution_get(execution_id)
236
- except ApiException as e:
237
- raise AsteroidAPIError(f"Failed to get execution: {e}") from e
238
-
239
- def wait_for_execution_result(
240
- self,
241
- execution_id: str,
242
- interval: float = 1.0,
243
- timeout: float = 3600.0
244
- ) -> ExecutionResult:
245
- """
246
- Wait for an execution to reach a terminal state and return the result.
247
-
248
- Continuously polls the execution until it's either "completed",
249
- "cancelled", or "failed".
250
-
251
- Args:
252
- execution_id: The execution identifier
253
- interval: Polling interval in seconds (default is 1.0)
254
- timeout: Maximum wait time in seconds (default is 3600 - 1 hour)
255
-
256
- Returns:
257
- The execution result object
258
-
259
- Raises:
260
- ValueError: If interval or timeout parameters are invalid
261
- TimeoutError: If the execution times out
262
- ExecutionError: If the execution ends as "cancelled" or "failed"
263
-
264
- Example:
265
- result = client.wait_for_execution_result(execution_id, interval=2.0)
266
- print(result.outcome, result.reasoning)
267
- """
268
- # Validate input parameters
269
- if interval <= 0:
270
- raise ValueError("interval must be positive")
271
- if timeout <= 0:
272
- raise ValueError("timeout must be positive")
273
- start_time = time.time()
274
-
275
- while True:
276
- elapsed_time = time.time() - start_time
277
- if elapsed_time >= timeout:
278
- raise TimeoutError(f"Execution {execution_id} timed out after {timeout}s")
279
-
280
- execution = self.get_execution(execution_id)
281
- current_status = execution.status
282
-
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
- )
295
-
296
- # Wait for the specified interval before polling again
297
- time.sleep(interval)
298
-
299
- def upload_execution_files(
300
- self,
301
- execution_id: str,
302
- files: List[Union[bytes, str, Tuple[str, bytes]]],
303
- default_filename: str = "file.txt"
304
- ) -> str:
305
- """
306
- Upload files to a running execution.
307
-
308
- Use this method to upload files to an execution that is already in progress.
309
- If you want to attach files to an execution before it starts, use stage_temp_files instead.
310
-
311
- Args:
312
- execution_id: The execution identifier
313
- files: List of files to upload. Each file can be:
314
- - bytes: Raw file content (will use default_filename)
315
- - str: File path as string (will read file and use filename)
316
- - Tuple[str, bytes]: (filename, file_content) tuple
317
- default_filename: Default filename to use when file is provided as bytes
318
-
319
- Returns:
320
- Success message from the API
321
-
322
- Raises:
323
- AsteroidAPIError: If the upload request fails
324
-
325
- Example:
326
- # Upload with file content
327
- with open('hello.txt', 'r') as f:
328
- file_content = f.read()
329
-
330
- response = client.upload_execution_files(execution_id, [file_content.encode()])
331
-
332
- # Upload with filename and content
333
- files = [('hello.txt', file_content.encode())]
334
- response = client.upload_execution_files(execution_id, files)
335
-
336
- # Or create content directly
337
- hello_content = "Hello World!".encode()
338
- response = client.upload_execution_files(execution_id, [hello_content])
339
- """
340
- try:
341
- # Process files to ensure proper format for the V2 API
342
- processed_files = []
343
- for file_item in files:
344
- if isinstance(file_item, tuple):
345
- # Already in (filename, content) format
346
- filename, content = file_item
347
- if isinstance(content, str):
348
- content = content.encode()
349
- processed_files.append((filename, content))
350
- elif isinstance(file_item, str):
351
- # Check if string is a file path that exists, otherwise treat as content
352
- if os.path.isfile(file_item):
353
- # File path - read the file
354
- filename = os.path.basename(file_item)
355
- with open(file_item, 'rb') as f:
356
- content = f.read()
357
- processed_files.append((filename, content))
358
- else:
359
- # String content - encode and use default filename
360
- content = file_item.encode()
361
- processed_files.append((default_filename, content))
362
- elif isinstance(file_item, bytes):
363
- # Raw bytes - use default filename
364
- processed_files.append((default_filename, file_item))
365
- else:
366
- # Other types - convert to string content and encode
367
- content = str(file_item).encode()
368
- processed_files.append((default_filename, content))
369
-
370
- response = self.agents_v2_files_api.execution_context_files_upload(execution_id, files=processed_files)
371
- return response
372
- except ApiException as e:
373
- raise AsteroidAPIError(f"Failed to upload execution files: {e}") from e
374
-
375
- # --- V1 (Agent Profiles) ---
376
-
377
- def get_agent_profiles(self, organization_id: str) -> List[AgentProfile]:
378
- """
379
- Get a list of agent profiles for a specific organization.
380
-
381
- Args:
382
- organization_id: The organization identifier (required)
383
- Returns:
384
- A list of agent profiles
385
- Raises:
386
- Exception: If the agent profiles request fails
387
- Example:
388
- profiles = client.get_agent_profiles("org-123")
389
- """
390
- try:
391
- response = self.agent_profile_api.get_agent_profiles(organization_id=organization_id)
392
- return response # response is already a List[AgentProfile]
393
- except ApiException as e:
394
- raise AsteroidAPIError(f"Failed to get agent profiles: {e}") from e
395
- def get_agent_profile(self, profile_id: str) -> AgentProfile:
396
- """
397
- Get an agent profile by ID.
398
- Args:
399
- profile_id: The ID of the agent profile
400
- Returns:
401
- The agent profile
402
- Raises:
403
- Exception: If the agent profile request fails
404
- Example:
405
- profile = client.get_agent_profile("profile_id")
406
- """
407
- try:
408
- response = self.agent_profile_api.get_agent_profile(profile_id)
409
- return response
410
- except ApiException as e:
411
- raise AsteroidAPIError(f"Failed to get agent profile: {e}") from e
412
-
413
- def create_agent_profile(self, request: CreateAgentProfileRequest) -> AgentProfile:
414
- """
415
- Create an agent profile with automatic credential encryption.
416
-
417
- Args:
418
- request: The request object
419
- Returns:
420
- The agent profile
421
- Raises:
422
- Exception: If the agent profile creation fails
423
- Example:
424
- request = CreateAgentProfileRequest(
425
- name="My Agent Profile",
426
- description="This is my agent profile",
427
- organization_id="org-123",
428
- proxy_cc=CountryCode.US,
429
- proxy_type=ProxyType.RESIDENTIAL,
430
- captcha_solver_active=True,
431
- sticky_ip=True,
432
- credentials=[Credential(name="user", data="password")]
433
- )
434
- profile = client.create_agent_profile(request)
435
- """
436
- try:
437
- # Create a copy to avoid modifying the original request
438
- processed_request = request
439
-
440
- # If credentials are provided, encrypt them before sending
441
- if request.credentials and len(request.credentials) > 0:
442
- # Get the public key for encryption
443
- public_key = self.get_credentials_public_key()
444
-
445
- # Encrypt each credential's data field
446
- encrypted_credentials = []
447
- for credential in request.credentials:
448
- encrypted_credential = Credential(
449
- name=credential.name,
450
- data=encrypt_with_public_key(credential.data, public_key),
451
- id=credential.id,
452
- created_at=credential.created_at
453
- )
454
- encrypted_credentials.append(encrypted_credential)
455
-
456
- # Create new request with encrypted credentials
457
- processed_request = CreateAgentProfileRequest(
458
- name=request.name,
459
- description=request.description,
460
- organization_id=request.organization_id,
461
- proxy_cc=request.proxy_cc,
462
- proxy_type=request.proxy_type,
463
- captcha_solver_active=request.captcha_solver_active,
464
- sticky_ip=request.sticky_ip,
465
- credentials=encrypted_credentials
466
- )
467
-
468
- response = self.agent_profile_api.create_agent_profile(processed_request)
469
- return response
470
- except ApiException as e:
471
- raise AsteroidAPIError(f"Failed to create agent profile: {e}") from e
472
- def update_agent_profile(self, profile_id: str, request: UpdateAgentProfileRequest) -> AgentProfile:
473
- """
474
- Update an agent profile with automatic credential encryption.
475
-
476
- Args:
477
- profile_id: The ID of the agent profile
478
- request: The request object
479
- Returns:
480
- The agent profile
481
- Raises:
482
- Exception: If the agent profile update fails
483
- Example:
484
- request = UpdateAgentProfileRequest(
485
- name="My Agent Profile",
486
- description="This is my agent profile",
487
- credentials_to_add=[Credential(name="api_key", data="secret")]
488
- )
489
- profile = client.update_agent_profile("profile_id", request)
490
- """
491
- try:
492
- # Create a copy to avoid modifying the original request
493
- processed_request = request
494
-
495
- # If credentials_to_add are provided, encrypt them before sending
496
- if request.credentials_to_add and len(request.credentials_to_add) > 0:
497
- # Get the public key for encryption
498
- public_key = self.get_credentials_public_key()
499
-
500
- # Encrypt the data field of each credential to add
501
- encrypted_credentials_to_add = []
502
- for credential in request.credentials_to_add:
503
- encrypted_credential = Credential(
504
- name=credential.name,
505
- data=encrypt_with_public_key(credential.data, public_key),
506
- id=credential.id,
507
- created_at=credential.created_at
508
- )
509
- encrypted_credentials_to_add.append(encrypted_credential)
510
-
511
- # Create new request with encrypted credentials
512
- processed_request = UpdateAgentProfileRequest(
513
- name=request.name,
514
- description=request.description,
515
- proxy_cc=request.proxy_cc,
516
- proxy_type=request.proxy_type,
517
- captcha_solver_active=request.captcha_solver_active,
518
- sticky_ip=request.sticky_ip,
519
- credentials_to_add=encrypted_credentials_to_add,
520
- credentials_to_delete=request.credentials_to_delete
521
- )
522
-
523
- response = self.agent_profile_api.update_agent_profile(profile_id, processed_request)
524
- return response
525
- except ApiException as e:
526
- raise AsteroidAPIError(f"Failed to update agent profile: {e}") from e
527
- def delete_agent_profile(self, profile_id: str) -> DeleteAgentProfile200Response:
528
- """
529
- Delete an agent profile.
530
- Args:
531
- profile_id: The ID of the agent profile
532
- Returns:
533
- Confirmation message from the server
534
- Raises:
535
- Exception: If the agent profile deletion fails
536
- Example:
537
- response = client.delete_agent_profile("profile_id")
538
- """
539
- try:
540
- response = self.agent_profile_api.delete_agent_profile(profile_id)
541
- return response
542
- except ApiException as e:
543
- raise AsteroidAPIError(f"Failed to delete agent profile: {e}") from e
544
-
545
- def get_credentials_public_key(self) -> str:
546
- """
547
- Get the public key for encrypting credentials.
548
-
549
- Returns:
550
- PEM-formatted RSA public key string
551
-
552
- Raises:
553
- Exception: If the public key request fails
554
-
555
- Example:
556
- public_key = client.get_credentials_public_key()
557
- """
558
- try:
559
- response = self.agent_profile_api.get_credentials_public_key()
560
- return response
561
- except ApiException as e:
562
- raise AsteroidAPIError(f"Failed to get credentials public key: {e}") from e
563
-
564
- def wait_for_agent_interaction(
565
- self,
566
- execution_id: str,
567
- poll_interval: float = 2.0,
568
- timeout: float = 3600.0
569
- ) -> AgentInteractionResult:
570
- """
571
- Wait for an agent interaction request or terminal state.
572
-
573
- This method polls an existing execution until it either:
574
- 1. Requests human input (paused_by_agent state)
575
- 2. Reaches a terminal state (completed, failed, cancelled)
576
- 3. Times out
577
-
578
- Unlike interactive_agent, this method doesn't start an execution or handle
579
- the response automatically - it just waits and reports what happened.
580
-
581
- Args:
582
- execution_id: The execution identifier for an already started execution
583
- poll_interval: How often to check for updates in seconds (default: 2.0)
584
- timeout: Maximum wait time in seconds (default: 3600 - 1 hour)
585
-
586
- Returns:
587
- AgentInteractionResult containing:
588
- - is_terminal: True if execution finished (completed/failed/cancelled)
589
- - status: Current execution status string
590
- - agent_message: Agent's message if requesting interaction (None if terminal)
591
- - execution_result: Final result if terminal state (None if requesting interaction)
592
-
593
- Raises:
594
- ValueError: If interval or timeout parameters are invalid
595
- TimeoutError: If the execution times out
596
- AsteroidAPIError: If API calls fail
597
-
598
- Example:
599
- # Start an execution first
600
- execution_id = client.execute_agent('agent-id', {'input': 'test'})
601
-
602
- # Wait for interaction or completion
603
- result = client.wait_for_agent_interaction(execution_id)
604
-
605
- if result.is_terminal:
606
- print(f"Execution finished with status: {result.status}")
607
- if result.execution_result:
608
- print(f"Result: {result.execution_result.outcome}")
609
- else:
610
- print(f"Agent requesting input: {result.agent_message}")
611
- # Send response
612
- client.add_message_to_execution(execution_id, "user response")
613
- # Wait again
614
- result = client.wait_for_agent_interaction(execution_id)
615
- """
616
- # Validate parameters
617
- if poll_interval <= 0:
618
- raise ValueError("poll_interval must be positive")
619
- if timeout <= 0:
620
- raise ValueError("timeout must be positive")
621
-
622
- start_time = time.time()
623
-
624
- while True:
625
- elapsed_time = time.time() - start_time
626
- if elapsed_time >= timeout:
627
- raise TimeoutError(f"Wait for interaction on execution {execution_id} timed out after {timeout}s")
628
-
629
- # Get current execution state
630
- execution = self.get_execution(execution_id)
631
- current_status = execution.status
632
- status_str = current_status.value.lower()
633
-
634
- # Handle terminal states
635
- if current_status == ExecutionStatus.COMPLETED:
636
- if execution.execution_result:
637
- return AgentInteractionResult(
638
- is_terminal=True,
639
- status=status_str,
640
- agent_message=None,
641
- execution_result=execution.execution_result
642
- )
643
- # Execution completed but result not ready yet, wait a bit more
644
- time.sleep(poll_interval)
645
- continue
646
-
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
- )
654
-
655
- # Handle agent interaction request
656
- elif current_status == ExecutionStatus.PAUSED_BY_AGENT:
657
- # Get the agent's message/request
658
- agent_message = self._extract_agent_request_message(execution_id)
659
- return AgentInteractionResult(
660
- is_terminal=False,
661
- status=status_str,
662
- agent_message=agent_message,
663
- execution_result=None
664
- )
665
-
666
- # Wait before next poll for non-terminal, non-interaction states
667
- time.sleep(poll_interval)
668
-
669
- def _extract_agent_request_message(self, execution_id: str) -> str:
670
- """
671
- Extract the agent's request message from recent activities.
672
-
673
- Args:
674
- execution_id: The execution identifier
675
-
676
- Returns:
677
- The agent's message or a default message if not found
678
- """
679
- try:
680
- activities = self.get_last_n_execution_activities(execution_id, 20)
681
-
682
- # Filter for human input requests
683
- human_input_requests = [
684
- activity for activity in activities
685
- if (hasattr(activity, 'payload') and
686
- activity.payload and
687
- getattr(activity.payload, 'activityType', None) == 'action_started')
688
- ]
689
-
690
- if human_input_requests:
691
- human_input_request = human_input_requests[0]
692
-
693
- # Extract message from payload data with robust error handling
694
- try:
695
- payload = human_input_request.payload
696
- if hasattr(payload, 'data') and payload.data:
697
- payload_data = payload.data
698
- if hasattr(payload_data, 'message') and payload_data.message:
699
- return str(payload_data.message)
700
- return 'Agent is requesting input'
701
- except (AttributeError, TypeError) as e:
702
- return 'Agent is requesting input (extraction failed)'
703
-
704
- return 'Agent is requesting input'
705
-
706
- except AsteroidAPIError as e:
707
- return 'Agent is requesting input (API error)'
708
- except Exception as e:
709
- return 'Agent is requesting input (extraction failed)'
710
-
711
- def __enter__(self):
712
- """Context manager entry."""
713
- return self
714
-
715
- def __exit__(self, exc_type, exc_value, tb):
716
- """Context manager exit: clean up API client connection pool."""
717
- try:
718
- # Try to grab the pool_manager; if any attr is missing, skip
719
- try:
720
- pool_manager = self.api_client.rest_client.pool_manager
721
- except AttributeError:
722
- pool_manager = None
723
-
724
- if pool_manager:
725
- pool_manager.clear()
726
- except Exception as e:
727
- pass
728
- return False
729
-
730
- def get_agents(self, org_id: str, page: int = 1, page_size: int = 100) -> List[Agent]:
731
- """
732
- Get a paginated list of agents for an organization.
733
- Args:
734
- org_id: The organization identifier
735
- page: The page number
736
- page_size: The page size
737
- Returns:
738
- A list of agents
739
- Raises:
740
- Exception: If the agents request fails
741
- Example:
742
- agents = client.get_agents("org_id", page=1, page_size=100)
743
- for agent in agents:
744
- print(f"Agent: {agent.name}")
745
- """
746
- response = self.agents_v2_agents_api.agent_list(organization_id=org_id, page=page, page_size=page_size)
747
- return response.items
748
-
749
- def get_executions(
750
- self,
751
- organization_id: str,
752
- page: int = 1,
753
- page_size: int = 20,
754
- execution_id: Optional[str] = None,
755
- agent_id: Optional[str] = None,
756
- status: Optional[List[str]] = None,
757
- agent_version: Optional[int] = None,
758
- created_after: Optional[str] = None,
759
- created_before: Optional[str] = None,
760
- human_labels: Optional[List[str]] = None,
761
- outcome_label: Optional[str] = None,
762
- metadata_key: Optional[str] = None,
763
- metadata_value: Optional[str] = None,
764
- sort_field: Optional[str] = None,
765
- sort_direction: Optional[str] = None,
766
- ) -> ExecutionsList200Response:
767
- """
768
- Get a paginated list of executions with optional filtering.
769
-
770
- Args:
771
- organization_id: The organization identifier (required)
772
- page: The page number (default: 1)
773
- page_size: The page size (default: 20)
774
- execution_id: Search by execution ID (partial, case-insensitive match)
775
- agent_id: Filter by agent ID
776
- status: Filter by execution status (can specify multiple)
777
- agent_version: Filter by agent version
778
- created_after: Filter executions created after this timestamp (ISO 8601)
779
- created_before: Filter executions created before this timestamp (ISO 8601)
780
- human_labels: Filter by human labels (can specify multiple label IDs)
781
- outcome_label: Filter by execution result outcome (partial, case-insensitive match)
782
- metadata_key: Filter by metadata key - must be used together with metadata_value
783
- metadata_value: Filter by metadata value - must be used together with metadata_key
784
- sort_field: Field to sort by (e.g., 'created_at')
785
- sort_direction: Sort direction ('asc' or 'desc')
786
-
787
- Returns:
788
- Paginated execution list with metadata
789
-
790
- Raises:
791
- AsteroidAPIError: If the executions request fails
792
-
793
- Example:
794
- # Get all executions for an organization
795
- result = client.get_executions(organization_id='org_123', page=1, page_size=20)
796
-
797
- # Filter by agent and status
798
- result = client.get_executions(
799
- organization_id='org_123',
800
- agent_id='agent_456',
801
- status=['completed', 'failed'],
802
- sort_field='created_at',
803
- sort_direction='desc'
804
- )
805
- """
806
- from datetime import datetime as dt
807
-
808
- # Convert status strings to enum if provided
809
- status_enums = None
810
- if status:
811
- status_enums = [ExecutionStatus(s) for s in status]
812
-
813
- # Convert sort_field and sort_direction to enums if provided
814
- sort_field_enum = ExecutionSortField(sort_field) if sort_field else None
815
- sort_direction_enum = SortDirection(sort_direction) if sort_direction else None
816
-
817
- # Parse datetime strings
818
- created_after_dt = dt.fromisoformat(created_after.replace('Z', '+00:00')) if created_after else None
819
- created_before_dt = dt.fromisoformat(created_before.replace('Z', '+00:00')) if created_before else None
820
-
821
- try:
822
- return self.agents_v2_execution_api.executions_list(
823
- page_size=page_size,
824
- page=page,
825
- organization_id=organization_id,
826
- execution_id=execution_id,
827
- agent_id=agent_id,
828
- status=status_enums,
829
- agent_version=agent_version,
830
- created_after=created_after_dt,
831
- created_before=created_before_dt,
832
- human_labels=human_labels,
833
- outcome_label=outcome_label,
834
- metadata_key=metadata_key,
835
- metadata_value=metadata_value,
836
- sort_field=sort_field_enum,
837
- sort_direction=sort_direction_enum,
838
- )
839
- except ApiException as e:
840
- raise AsteroidAPIError(f"Failed to get executions: {e}") from e
841
-
842
- def get_last_n_execution_activities(self, execution_id: str, n: int) -> List[ExecutionActivity]:
843
- """
844
- Get the last N execution activities for a given execution ID, sorted by their timestamp in descending order.
845
- Args:
846
- execution_id: The execution identifier
847
- n: The number of activities to return
848
- Returns:
849
- A list of execution activities
850
- Raises:
851
- Exception: If the execution activities request fails
852
- """
853
- return self.agents_v2_execution_api.execution_activities_get(execution_id, order="desc", limit=n)
854
- def add_message_to_execution(self, execution_id: str, message: str) -> None:
855
- """
856
- Add a message to an execution.
857
- Args:
858
- execution_id: The execution identifier
859
- message: The message to add
860
- Returns:
861
- None
862
- Raises:
863
- Exception: If the message addition fails
864
- Example:
865
- add_message_to_execution(client, "execution_id", "Hello, world!")
866
- """
867
- message_body = ExecutionUserMessagesAddTextBody(message=message)
868
- return self.agents_v2_execution_api.execution_user_messages_add(execution_id, message_body)
869
-
870
- def get_execution_files(self, execution_id: str) -> List[File]:
871
- """
872
- Get a list of files associated with an execution.
873
- Args:
874
- execution_id: The execution identifier
875
- Returns:
876
- A list of files associated with the execution
877
- Raises:
878
- AsteroidAPIError: If the files request fails
879
- Example:
880
- files = client.get_execution_files("execution_id")
881
- for file in files:
882
- print(f"File: {file.file_name}, Size: {file.file_size}")
883
- """
884
- try:
885
- return self.agents_v2_files_api.execution_context_files_get(execution_id)
886
- except ApiException as e:
887
- raise AsteroidAPIError(f"Failed to get execution files: {e}") from e
888
-
889
- def stage_temp_files(
890
- self,
891
- organization_id: str,
892
- files: List[Union[bytes, str, Tuple[str, bytes]]],
893
- default_filename: str = "file.txt"
894
- ) -> List[TempFile]:
895
- """
896
- Stage files before starting an execution.
897
-
898
- Use this method to pre-upload files that will be attached to an execution when it starts.
899
- The returned TempFile objects can be passed to execute_agent's temp_files parameter.
900
-
901
- Args:
902
- organization_id: The organization identifier
903
- files: List of files to stage. Each file can be:
904
- - bytes: Raw file content (will use default_filename)
905
- - str: File path as string (will read file and use filename)
906
- - Tuple[str, bytes]: (filename, file_content) tuple
907
- default_filename: Default filename to use when file is provided as bytes
908
-
909
- Returns:
910
- List of TempFile objects that can be passed to execute_agent
911
-
912
- Raises:
913
- AsteroidAPIError: If the staging request fails
914
-
915
- Example:
916
- # Stage files before execution
917
- temp_files = client.stage_temp_files("org-123", [
918
- ("data.csv", csv_content.encode()),
919
- "/path/to/document.pdf"
920
- ])
921
-
922
- # Use staged files when executing agent
923
- execution_id = client.execute_agent(
924
- agent_id="my-agent",
925
- execution_data={"input": "Process these files"},
926
- temp_files=temp_files
927
- )
928
- """
929
- try:
930
- # Process files to ensure proper format for the V2 API
931
- processed_files = []
932
- for file_item in files:
933
- if isinstance(file_item, tuple):
934
- # Already in (filename, content) format
935
- filename, content = file_item
936
- if isinstance(content, str):
937
- content = content.encode()
938
- processed_files.append((filename, content))
939
- elif isinstance(file_item, str):
940
- # Check if string is a file path that exists, otherwise treat as content
941
- if os.path.isfile(file_item):
942
- # File path - read the file
943
- filename = os.path.basename(file_item)
944
- with open(file_item, 'rb') as f:
945
- content = f.read()
946
- processed_files.append((filename, content))
947
- else:
948
- # String content - encode and use default filename
949
- content = file_item.encode()
950
- processed_files.append((default_filename, content))
951
- elif isinstance(file_item, bytes):
952
- # Raw bytes - use default filename
953
- processed_files.append((default_filename, file_item))
954
- else:
955
- # Other types - convert to string content and encode
956
- content = str(file_item).encode()
957
- processed_files.append((default_filename, content))
958
-
959
- response = self.agents_v2_files_api.temp_files_stage(organization_id, files=processed_files)
960
- return response.temp_files
961
- except ApiException as e:
962
- raise AsteroidAPIError(f"Failed to stage temp files: {e}") from e
963
-
964
- def download_execution_file(self, file: File, download_path: Union[str, Path],
965
- create_dirs: bool = True, timeout: int = 30) -> str:
966
- """
967
- Download a file from an execution using its signed URL.
968
-
969
- Args:
970
- file: The File object containing the signed URL and metadata
971
- download_path: Path where the file should be saved. Can be a directory or full file path
972
- create_dirs: Whether to create parent directories if they don't exist (default: True)
973
- timeout: Request timeout in seconds (default: 30)
974
-
975
- Returns:
976
- The full path where the file was saved
977
-
978
- Raises:
979
- AsteroidAPIError: If the download fails
980
- FileNotFoundError: If the parent directory doesn't exist and create_dirs is False
981
-
982
- Example:
983
- files = client.get_execution_files("execution_id")
984
- for file in files:
985
- # Download to specific directory
986
- saved_path = client.download_execution_file(file, "/path/to/downloads/")
987
- print(f"Downloaded {file.file_name} to {saved_path}")
988
-
989
- # Download with specific filename
990
- saved_path = client.download_execution_file(file, "/path/to/downloads/my_file.txt")
991
- print(f"Downloaded to {saved_path}")
992
- """
993
- final_path = None
994
- try:
995
- # Convert to Path object for easier manipulation
996
- download_path = Path(download_path)
997
-
998
- # Determine the final file path
999
- if download_path.is_dir() or str(download_path).endswith('/'):
1000
- # If download_path is a directory, use the original filename
1001
- final_path = download_path / file.file_name
1002
- else:
1003
- # If download_path includes a filename, use it as-is
1004
- final_path = download_path
1005
-
1006
- # Create parent directories if needed
1007
- if create_dirs:
1008
- final_path.parent.mkdir(parents=True, exist_ok=True)
1009
- elif not final_path.parent.exists():
1010
- raise FileNotFoundError(f"Parent directory does not exist: {final_path.parent}")
1011
-
1012
- # Download the file using the signed URL
1013
- response = requests.get(file.signed_url, timeout=timeout, stream=True)
1014
- response.raise_for_status()
1015
-
1016
- # Verify content length if available
1017
- expected_size = file.file_size
1018
- content_length = response.headers.get('content-length')
1019
- if content_length and int(content_length) != expected_size:
1020
- raise AsteroidAPIError(
1021
- f"Content length mismatch: expected {expected_size}, got {content_length}"
1022
- )
1023
-
1024
- # Write the file in chunks to handle large files efficiently
1025
- chunk_size = 8192
1026
- total_size = 0
1027
-
1028
- with open(final_path, 'wb') as f:
1029
- for chunk in response.iter_content(chunk_size=chunk_size):
1030
- if chunk: # Filter out keep-alive chunks
1031
- f.write(chunk)
1032
- total_size += len(chunk)
1033
-
1034
- # Final verification of the downloaded file size
1035
- if total_size != expected_size:
1036
- raise AsteroidAPIError(
1037
- f"Downloaded file size mismatch: expected {expected_size}, got {total_size}"
1038
- )
1039
-
1040
- return str(final_path)
1041
-
1042
- except requests.exceptions.RequestException as e:
1043
- # Clean up partial file on network error
1044
- if final_path and final_path.exists():
1045
- final_path.unlink(missing_ok=True)
1046
- raise AsteroidAPIError(f"Failed to download file {file.file_name}: {e}") from e
1047
- except OSError as e:
1048
- # Clean up partial file on I/O error
1049
- if final_path and final_path.exists():
1050
- final_path.unlink(missing_ok=True)
1051
- raise AsteroidAPIError(f"Failed to save file {file.file_name}: {e}") from e
1052
- except AsteroidAPIError:
1053
- # Clean up partial file on size mismatch or other API errors
1054
- if final_path and final_path.exists():
1055
- final_path.unlink(missing_ok=True)
1056
- raise
1057
- except Exception as e:
1058
- # Clean up partial file on unexpected error
1059
- if final_path and final_path.exists():
1060
- final_path.unlink(missing_ok=True)
1061
- raise AsteroidAPIError(f"Unexpected error downloading file {file.file_name}: {e}") from e
1062
-
1063
- # Convenience functions that mirror the TypeScript SDK pattern
1064
- def create_client(api_key: str, base_url: Optional[str] = None) -> AsteroidClient:
1065
- """
1066
- Create an API client with a provided API key.
1067
-
1068
- This is a convenience function that creates an AsteroidClient instance.
1069
-
1070
- Args:
1071
- api_key: Your API key
1072
- base_url: Optional base URL
1073
-
1074
- Returns:
1075
- A configured AsteroidClient instance
1076
-
1077
- Example:
1078
- client = create_client('your-api-key')
1079
- """
1080
- return AsteroidClient(api_key, base_url)
1081
-
1082
- # --- V2 ---
1083
-
1084
- def execute_agent(
1085
- client: AsteroidClient,
1086
- agent_id: str,
1087
- dynamic_data: Optional[Dict[str, Any]] = None,
1088
- agent_profile_id: Optional[str] = None,
1089
- metadata: Optional[Dict[str, Any]] = None,
1090
- temp_files: Optional[List[TempFile]] = None,
1091
- version: Optional[int] = None,
1092
- ) -> str:
1093
- """
1094
- Execute an agent with the provided parameters.
1095
-
1096
- Args:
1097
- client: The AsteroidClient instance
1098
- agent_id: The ID of the agent to execute
1099
- dynamic_data: Dynamic data to be merged into the placeholders defined in prompts
1100
- agent_profile_id: Optional ID of the agent profile to use
1101
- metadata: Optional metadata key-value pairs for organizing and filtering executions
1102
- temp_files: Optional list of temporary files to attach (must be pre-uploaded using stage_temp_files)
1103
- version: Optional version of the agent to execute. If not provided, the latest version will be used.
1104
-
1105
- Returns:
1106
- The execution ID
1107
-
1108
- Example:
1109
- execution_id = execute_agent(client, 'my-agent-id', {'input': 'some dynamic value'})
1110
- execution_id = execute_agent(client, 'my-agent-id', {'input': 'value'}, version=3)
1111
- """
1112
- return client.execute_agent(
1113
- agent_id,
1114
- dynamic_data,
1115
- agent_profile_id,
1116
- metadata,
1117
- temp_files,
1118
- version,
1119
- )
1120
-
1121
- def get_execution(client: AsteroidClient, execution_id: str) -> ExecutionListItem:
1122
- """
1123
- Get a single execution by ID with all details.
1124
-
1125
- This function returns comprehensive execution information including status,
1126
- result, browser recording URL, and other metadata.
1127
-
1128
- Args:
1129
- client: The AsteroidClient instance
1130
- execution_id: The execution identifier
1131
-
1132
- Returns:
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
1141
-
1142
- Raises:
1143
- AsteroidAPIError: If the request fails
1144
-
1145
- Example:
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}")
1152
- """
1153
- return client.get_execution(execution_id)
1154
-
1155
-
1156
- def wait_for_execution_result(
1157
- client: AsteroidClient,
1158
- execution_id: str,
1159
- interval: float = 1.0,
1160
- timeout: float = 3600.0
1161
- ) -> ExecutionResult:
1162
- """
1163
- Wait for an execution to reach a terminal state and return the result.
1164
-
1165
- Args:
1166
- client: The AsteroidClient instance
1167
- execution_id: The execution identifier
1168
- interval: Polling interval in seconds (default is 1.0)
1169
- timeout: Maximum wait time in seconds (default is 3600 - 1 hour)
1170
-
1171
- Returns:
1172
- The execution result object
1173
-
1174
- Raises:
1175
- TimeoutError: If the execution times out
1176
- ExecutionError: If the execution ends as "cancelled" or "failed"
1177
-
1178
- Example:
1179
- result = wait_for_execution_result(client, execution_id, interval=2.0)
1180
- print(result.outcome, result.reasoning)
1181
- """
1182
- return client.wait_for_execution_result(execution_id, interval, timeout)
1183
-
1184
-
1185
- def upload_execution_files(
1186
- client: AsteroidClient,
1187
- execution_id: str,
1188
- files: List[Union[bytes, str, Tuple[str, bytes]]],
1189
- default_filename: str = "file.txt"
1190
- ) -> str:
1191
- """
1192
- Upload files to a running execution.
1193
-
1194
- Use this function to upload files to an execution that is already in progress.
1195
- If you want to attach files to an execution before it starts, use stage_temp_files instead.
1196
-
1197
- Args:
1198
- client: The AsteroidClient instance
1199
- execution_id: The execution identifier
1200
- files: List of files to upload
1201
- default_filename: Default filename to use when file is provided as bytes
1202
-
1203
- Returns:
1204
- Success message from the API
1205
-
1206
- Example:
1207
- # Create a simple text file with "Hello World!" content
1208
- hello_content = "Hello World!".encode()
1209
- response = upload_execution_files(client, execution_id, [hello_content])
1210
-
1211
- # Or specify filename with content
1212
- files = [('hello.txt', "Hello World!".encode())]
1213
- response = upload_execution_files(client, execution_id, files)
1214
- """
1215
- return client.upload_execution_files(execution_id, files, default_filename)
1216
-
1217
-
1218
- def stage_temp_files(
1219
- client: AsteroidClient,
1220
- organization_id: str,
1221
- files: List[Union[bytes, str, Tuple[str, bytes]]],
1222
- default_filename: str = "file.txt"
1223
- ) -> List[TempFile]:
1224
- """
1225
- Stage files before starting an execution.
1226
-
1227
- Use this function to pre-upload files that will be attached to an execution when it starts.
1228
- The returned TempFile objects can be passed to execute_agent's temp_files parameter.
1229
-
1230
- Args:
1231
- client: The AsteroidClient instance
1232
- organization_id: The organization identifier
1233
- files: List of files to stage. Each file can be:
1234
- - bytes: Raw file content (will use default_filename)
1235
- - str: File path as string (will read file and use filename)
1236
- - Tuple[str, bytes]: (filename, file_content) tuple
1237
- default_filename: Default filename to use when file is provided as bytes
1238
-
1239
- Returns:
1240
- List of TempFile objects that can be passed to execute_agent
1241
-
1242
- Raises:
1243
- AsteroidAPIError: If the staging request fails
1244
-
1245
- Example:
1246
- # Stage files before execution
1247
- temp_files = stage_temp_files(client, "org-123", [
1248
- ("data.csv", csv_content.encode()),
1249
- "/path/to/document.pdf"
1250
- ])
1251
-
1252
- # Use staged files when executing agent
1253
- execution_id = execute_agent(
1254
- client,
1255
- agent_id="my-agent",
1256
- execution_data={"input": "Process these files"},
1257
- temp_files=temp_files
1258
- )
1259
- """
1260
- return client.stage_temp_files(organization_id, files, default_filename)
1261
-
1262
-
1263
- # --- V1 (Agent Profiles) ---
1264
-
1265
- def get_agent_profiles(client: AsteroidClient, organization_id: Optional[str] = None) -> List[AgentProfile]:
1266
- """
1267
- Get a list of agent profiles.
1268
- Args:
1269
- client: The AsteroidClient instance
1270
- organization_id: The organization identifier (optional) Returns all agent profiles if no organization_id is provided.
1271
- Returns:
1272
- A list of agent profiles
1273
- Raises:
1274
- Exception: If the agent profiles request fails
1275
- Example:
1276
- profiles = get_agent_profiles(client, "org-123")
1277
- """
1278
- return client.get_agent_profiles(organization_id)
1279
- def get_agent_profile(client: AsteroidClient, profile_id: str) -> AgentProfile:
1280
- """
1281
- Get an agent profile by ID.
1282
- Args:
1283
- client: The AsteroidClient instance
1284
- profile_id: The ID of the agent profile
1285
- Returns:
1286
- The agent profile
1287
- Raises:
1288
- Exception: If the agent profile request fails
1289
- Example:
1290
- profile = get_agent_profile(client, "profile_id")
1291
- """
1292
- return client.get_agent_profile(profile_id)
1293
- def create_agent_profile(client: AsteroidClient, request: CreateAgentProfileRequest) -> AgentProfile:
1294
- """
1295
- Create an agent profile.
1296
- Args:
1297
- client: The AsteroidClient instance
1298
- request: The request object
1299
- Returns:
1300
- The agent profile
1301
- Raises:
1302
- Exception: If the agent profile creation fails
1303
- Example:
1304
- request = CreateAgentProfileRequest(
1305
- name="My Agent Profile",
1306
- description="This is my agent profile",
1307
- organization_id="org-123",
1308
- proxy_cc=CountryCode.US,
1309
- proxy_type=ProxyType.RESIDENTIAL,
1310
- captcha_solver_active=True,
1311
- sticky_ip=True,
1312
- credentials=[Credential(name="user", data="password")]
1313
- )
1314
- profile = create_agent_profile(client, request)
1315
- """
1316
- return client.create_agent_profile(request)
1317
- def update_agent_profile(client: AsteroidClient, profile_id: str, request: UpdateAgentProfileRequest) -> AgentProfile:
1318
- """
1319
- Update an agent profile with the provided request.
1320
- Args:
1321
- client: The AsteroidClient instance
1322
- profile_id: The ID of the agent profile
1323
- request: The request object
1324
- Returns:
1325
- The agent profile
1326
- Raises:
1327
- Exception: If the agent profile update fails
1328
- Example:
1329
- request = UpdateAgentProfileRequest(
1330
- name="My Agent Profile",
1331
- description="This is my agent profile",
1332
- organization_id="org-123",
1333
- )
1334
- profile = update_agent_profile(client, "profile_id", request)
1335
- """
1336
- return client.update_agent_profile(profile_id, request)
1337
- def delete_agent_profile(client: AsteroidClient, profile_id: str) -> DeleteAgentProfile200Response:
1338
- """
1339
- Delete an agent profile.
1340
- Args:
1341
- client: The AsteroidClient instance
1342
- profile_id: The ID of the agent profile
1343
- Returns:
1344
- The agent profile
1345
- Raises:
1346
- Exception: If the agent profile deletion fails
1347
- Example:
1348
- profile_deleted =delete_agent_profile(client, "profile_id")
1349
- """
1350
- return client.delete_agent_profile(profile_id)
1351
-
1352
- def get_credentials_public_key(client: AsteroidClient) -> str:
1353
- """
1354
- Get the public key for encrypting credentials.
1355
-
1356
- Args:
1357
- client: The AsteroidClient instance
1358
-
1359
- Returns:
1360
- PEM-formatted RSA public key string
1361
-
1362
- Example:
1363
- public_key = get_credentials_public_key(client)
1364
- """
1365
- return client.get_credentials_public_key()
1366
-
1367
- # --- V2 ---
1368
-
1369
- def get_agents(client: AsteroidClient, org_id: str, page: int = 1, page_size: int = 100) -> List[Agent]:
1370
- """
1371
- Get a paginated list of agents for an organization.
1372
- Args:
1373
- client: The AsteroidClient instance
1374
- org_id: The organization identifier
1375
- page: The page number
1376
- page_size: The page size
1377
- Returns:
1378
- A list of agents
1379
- Raises:
1380
- Exception: If the agents request fails
1381
- Example:
1382
- agents = get_agents(client, "org_id", page=1, page_size=100)
1383
- for agent in agents:
1384
- print(f"Agent: {agent.name}")
1385
- """
1386
- return client.get_agents(org_id, page, page_size)
1387
-
1388
- def get_executions(
1389
- client: AsteroidClient,
1390
- organization_id: str,
1391
- page: int = 1,
1392
- page_size: int = 20,
1393
- execution_id: Optional[str] = None,
1394
- agent_id: Optional[str] = None,
1395
- status: Optional[List[str]] = None,
1396
- agent_version: Optional[int] = None,
1397
- created_after: Optional[str] = None,
1398
- created_before: Optional[str] = None,
1399
- human_labels: Optional[List[str]] = None,
1400
- outcome_label: Optional[str] = None,
1401
- metadata_key: Optional[str] = None,
1402
- metadata_value: Optional[str] = None,
1403
- sort_field: Optional[str] = None,
1404
- sort_direction: Optional[str] = None,
1405
- ) -> ExecutionsList200Response:
1406
- """
1407
- Get a paginated list of executions with optional filtering.
1408
-
1409
- Args:
1410
- client: The AsteroidClient instance
1411
- organization_id: The organization identifier (required)
1412
- page: The page number (default: 1)
1413
- page_size: The page size (default: 20)
1414
- execution_id: Search by execution ID (partial, case-insensitive match)
1415
- agent_id: Filter by agent ID
1416
- status: Filter by execution status (can specify multiple)
1417
- agent_version: Filter by agent version
1418
- created_after: Filter executions created after this timestamp (ISO 8601)
1419
- created_before: Filter executions created before this timestamp (ISO 8601)
1420
- human_labels: Filter by human labels (can specify multiple label IDs)
1421
- outcome_label: Filter by execution result outcome (partial, case-insensitive match)
1422
- metadata_key: Filter by metadata key - must be used together with metadata_value
1423
- metadata_value: Filter by metadata value - must be used together with metadata_key
1424
- sort_field: Field to sort by (e.g., 'created_at')
1425
- sort_direction: Sort direction ('asc' or 'desc')
1426
-
1427
- Returns:
1428
- Paginated execution list with metadata
1429
-
1430
- Example:
1431
- result = get_executions(client, organization_id='org_123', page=1, page_size=20)
1432
- """
1433
- return client.get_executions(
1434
- organization_id=organization_id,
1435
- page=page,
1436
- page_size=page_size,
1437
- execution_id=execution_id,
1438
- agent_id=agent_id,
1439
- status=status,
1440
- agent_version=agent_version,
1441
- created_after=created_after,
1442
- created_before=created_before,
1443
- human_labels=human_labels,
1444
- outcome_label=outcome_label,
1445
- metadata_key=metadata_key,
1446
- metadata_value=metadata_value,
1447
- sort_field=sort_field,
1448
- sort_direction=sort_direction,
1449
- )
1450
-
1451
- def get_last_n_execution_activities(client: AsteroidClient, execution_id: str, n: int) -> List[ExecutionActivity]:
1452
- """
1453
- Get the last N execution activities for a given execution ID, sorted by their timestamp in descending order.
1454
- Args:
1455
- client: The AsteroidClient instance
1456
- execution_id: The execution identifier
1457
- n: The number of activities to return
1458
- Returns:
1459
- A list of execution activities
1460
- Raises:
1461
- Exception: If the execution activities request fails
1462
- Example:
1463
- activities = get_last_n_execution_activities(client, "execution_id", 10)
1464
- """
1465
- return client.get_last_n_execution_activities(execution_id, n)
1466
-
1467
- def add_message_to_execution(client: AsteroidClient, execution_id: str, message: str) -> None:
1468
- """
1469
- Add a message to an execution.
1470
- Args:
1471
- client: The AsteroidClient instance
1472
- execution_id: The execution identifier
1473
- message: The message to add
1474
- Returns:
1475
- None
1476
- Raises:
1477
- Exception: If the message addition fails
1478
- Example:
1479
- add_message_to_execution(client, "execution_id", "Hello, world!")
1480
- """
1481
- return client.add_message_to_execution(execution_id, message)
1482
-
1483
- def get_execution_files(client: AsteroidClient, execution_id: str) -> List[File]:
1484
- """
1485
- Get a list of files associated with an execution.
1486
- Args:
1487
- client: The AsteroidClient instance
1488
- execution_id: The execution identifier
1489
- Returns:
1490
- A list of files associated with the execution
1491
- Raises:
1492
- Exception: If the files request fails
1493
- Example:
1494
- files = get_execution_files(client, "execution_id")
1495
- for file in files:
1496
- print(f"File: {file.file_name}, Size: {file.file_size}")
1497
- """
1498
- return client.get_execution_files(execution_id)
1499
-
1500
- def download_execution_file(client: AsteroidClient, file: File, download_path: Union[str, Path],
1501
- create_dirs: bool = True, timeout: int = 30) -> str:
1502
- """
1503
- Download a file from an execution using its signed URL.
1504
-
1505
- Args:
1506
- client: The AsteroidClient instance
1507
- file: The File object containing the signed URL and metadata
1508
- download_path: Path where the file should be saved. Can be a directory or full file path
1509
- create_dirs: Whether to create parent directories if they don't exist (default: True)
1510
- timeout: Request timeout in seconds (default: 30)
1511
-
1512
- Returns:
1513
- The full path where the file was saved
1514
-
1515
- Raises:
1516
- AsteroidAPIError: If the download fails
1517
- FileNotFoundError: If the parent directory doesn't exist and create_dirs is False
1518
-
1519
- Example:
1520
- files = get_execution_files(client, "execution_id")
1521
- for file in files:
1522
- # Download to specific directory
1523
- saved_path = download_execution_file(client, file, "/path/to/downloads/")
1524
- print(f"Downloaded {file.file_name} to {saved_path}")
1525
-
1526
- # Download with specific filename
1527
- saved_path = download_execution_file(client, file, "/path/to/downloads/my_file.txt")
1528
- print(f"Downloaded to {saved_path}")
1529
- """
1530
- return client.download_execution_file(file, download_path, create_dirs, timeout)
1531
-
1532
-
1533
-
1534
- def wait_for_agent_interaction(
1535
- client: AsteroidClient,
1536
- execution_id: str,
1537
- poll_interval: float = 2.0,
1538
- timeout: float = 3600.0
1539
- ) -> AgentInteractionResult:
1540
- """
1541
- Wait for an agent interaction request or terminal state.
1542
-
1543
- This convenience function provides the same functionality as the AsteroidClient.wait_for_agent_interaction method.
1544
-
1545
- Args:
1546
- client: The AsteroidClient instance
1547
- execution_id: The execution identifier for an already started execution
1548
- poll_interval: How often to check for updates in seconds (default: 2.0)
1549
- timeout: Maximum wait time in seconds (default: 3600 - 1 hour)
1550
-
1551
- Returns:
1552
- AgentInteractionResult containing:
1553
- - is_terminal: True if execution finished (completed/failed/cancelled)
1554
- - status: Current execution status string
1555
- - agent_message: Agent's message if requesting interaction (None if terminal)
1556
- - execution_result: Final result if terminal state (None if requesting interaction)
1557
-
1558
- Raises:
1559
- ValueError: If interval or timeout parameters are invalid
1560
- TimeoutError: If the execution times out
1561
- AsteroidAPIError: If API calls fail
1562
-
1563
- Example:
1564
- # Start an execution first
1565
- execution_id = execute_agent(client, 'agent-id', {'input': 'test'})
1566
-
1567
- # Wait for interaction or completion
1568
- result = wait_for_agent_interaction(client, execution_id)
1569
-
1570
- if result.is_terminal:
1571
- print(f"Execution finished with status: {result.status}")
1572
- if result.execution_result:
1573
- print(f"Result: {result.execution_result.outcome}")
1574
- else:
1575
- print(f"Agent requesting input: {result.agent_message}")
1576
- # Send response
1577
- add_message_to_execution(client, execution_id, "user response")
1578
- # Wait again
1579
- result = wait_for_agent_interaction(client, execution_id)
1580
- """
1581
- return client.wait_for_agent_interaction(
1582
- execution_id=execution_id,
1583
- poll_interval=poll_interval,
1584
- timeout=timeout
1585
- )
1586
-
1587
- # Re-export common types for convenience
1588
- __all__ = [
1589
- # Client
1590
- 'AsteroidClient',
1591
- 'create_client',
1592
- # Agent Execution (V2)
1593
- 'execute_agent',
1594
- 'get_execution',
1595
- 'get_executions',
1596
- 'wait_for_execution_result',
1597
- 'upload_execution_files',
1598
- 'stage_temp_files',
1599
- # Agent Profiles (V1)
1600
- 'get_agent_profiles',
1601
- 'get_agent_profile',
1602
- 'create_agent_profile',
1603
- 'update_agent_profile',
1604
- 'delete_agent_profile',
1605
- 'get_credentials_public_key',
1606
- # Agents (V2)
1607
- 'get_agents',
1608
- # Execution Activities (V2)
1609
- 'get_last_n_execution_activities',
1610
- 'add_message_to_execution',
1611
- 'get_execution_files',
1612
- 'download_execution_file',
1613
- 'wait_for_agent_interaction',
1614
- # Exceptions
1615
- 'AsteroidAPIError',
1616
- 'ExecutionError',
1617
- 'TimeoutError',
1618
- 'AgentInteractionResult',
1619
- # Types
1620
- 'TempFile',
1621
- 'TempFilesResponse',
1622
- 'ExecuteAgentRequest',
1623
- 'ExecutionListItem',
1624
- 'ExecutionResult',
1625
- 'ExecutionsList200Response',
1626
- 'ExecutionStatus',
1627
- 'ExecutionSortField',
1628
- 'SortDirection',
1629
- ]