asteroid-odyssey 1.3.13__py3-none-any.whl → 1.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- asteroid_odyssey/__init__.py +254 -82
- asteroid_odyssey/api/__init__.py +8 -0
- asteroid_odyssey/{agents_v1_gen/api/agent_profile_api.py → api/agent_profiles_api.py} +414 -281
- asteroid_odyssey/{agents_v2_gen/api → api}/agents_api.py +30 -30
- asteroid_odyssey/{agents_v2_gen/api → api}/execution_api.py +32 -49
- asteroid_odyssey/{agents_v2_gen/api → api}/files_api.py +5 -5
- asteroid_odyssey/{agents_v2_gen/api_client.py → api_client.py} +10 -6
- asteroid_odyssey/{agents_v2_gen/configuration.py → configuration.py} +11 -4
- asteroid_odyssey/models/__init__.py +118 -0
- asteroid_odyssey/{agents_v2_gen/models → models}/agent_list200_response.py +1 -1
- asteroid_odyssey/models/agent_profile_clear_browser_cache200_response.py +87 -0
- asteroid_odyssey/models/agent_profiles_list200_response.py +101 -0
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_base.py +3 -3
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_execute_agent_request.py +7 -5
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_completed_info.py +65 -37
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_completed_payload.py +8 -8
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_failed_payload.py +9 -9
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_started_info.py +50 -22
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_action_started_payload.py +10 -10
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_file_added_payload.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_payload_union.py +14 -14
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_playwright_script_generated_payload.py +9 -9
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_status_changed_payload.py +19 -19
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_transitioned_node_payload.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_workflow_updated_payload.py +1 -1
- asteroid_odyssey/models/agents_execution_agent_query_context_completed_details.py +98 -0
- asteroid_odyssey/models/agents_execution_agent_query_context_started_details.py +96 -0
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_cancelled_payload.py +1 -1
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_comment.py +10 -10
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_completed_payload.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_execution_result.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_ext_api_call_completed_details.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_failed_payload.py +5 -5
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_file_read_completed_details.py +3 -3
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_human_label.py +7 -7
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_list_item.py +33 -37
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_llm_call_started_details.py +1 -1
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_obs_snapshot_with_selectors_completed_details.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_write_completed_details.py +7 -7
- asteroid_odyssey/models/agents_execution_script_eval_completed_details.py +101 -0
- asteroid_odyssey/models/agents_execution_script_eval_started_details.py +100 -0
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_hybrid_playwright_completed_details.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_pad_run_function_completed_details.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_playwright_completed_details.py +6 -6
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_read_started_details.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_run_function_started_details.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_search_replace_completed_details.py +5 -5
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_search_replace_started_details.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_write_completed_details.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_terminal_payload.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_util_get_datetime_completed_details.py +4 -4
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_workflow_update.py +13 -13
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_files_file.py +11 -11
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_files_temp_files_response.py +1 -1
- asteroid_odyssey/{agents_v2_gen/models → models}/agents_graph_models_nodes_properties_playwright_script_llm_var.py +5 -5
- asteroid_odyssey/{agents_v1_gen/models/agent_profile.py → models/agents_profile_agent_profile.py} +37 -32
- asteroid_odyssey/{agents_v1_gen/models/cookie.py → models/agents_profile_cookie.py} +21 -26
- asteroid_odyssey/{agents_v1_gen/models/country_code.py → models/agents_profile_country_code.py} +5 -5
- asteroid_odyssey/{agents_v1_gen/models/create_agent_profile_request.py → models/agents_profile_create_agent_profile_request.py} +33 -28
- asteroid_odyssey/{agents_v1_gen/models/credential.py → models/agents_profile_credential.py} +13 -13
- asteroid_odyssey/models/agents_profile_operating_system.py +37 -0
- asteroid_odyssey/models/agents_profile_proxy_type.py +38 -0
- asteroid_odyssey/models/agents_profile_same_site.py +38 -0
- asteroid_odyssey/models/agents_profile_sort_field.py +38 -0
- asteroid_odyssey/models/agents_profile_update_agent_profile_request.py +129 -0
- asteroid_odyssey/{agents_v2_gen/models → models}/executions_list200_response.py +1 -1
- asteroid_odyssey/{agents_v2_gen/rest.py → rest.py} +2 -1
- asteroid_odyssey-1.6.1.dist-info/METADATA +64 -0
- asteroid_odyssey-1.6.1.dist-info/RECORD +119 -0
- asteroid_odyssey/agents_v1_gen/__init__.py +0 -53
- asteroid_odyssey/agents_v1_gen/api/__init__.py +0 -7
- asteroid_odyssey/agents_v1_gen/api/api_api.py +0 -516
- asteroid_odyssey/agents_v1_gen/api/execution_api.py +0 -1449
- asteroid_odyssey/agents_v1_gen/api_client.py +0 -797
- asteroid_odyssey/agents_v1_gen/configuration.py +0 -599
- asteroid_odyssey/agents_v1_gen/exceptions.py +0 -216
- asteroid_odyssey/agents_v1_gen/models/__init__.py +0 -34
- asteroid_odyssey/agents_v1_gen/models/browser_session_recording_response.py +0 -87
- asteroid_odyssey/agents_v1_gen/models/delete_agent_profile200_response.py +0 -87
- asteroid_odyssey/agents_v1_gen/models/error_response.py +0 -87
- asteroid_odyssey/agents_v1_gen/models/execution_response.py +0 -87
- asteroid_odyssey/agents_v1_gen/models/execution_result.py +0 -101
- asteroid_odyssey/agents_v1_gen/models/execution_result_response.py +0 -100
- asteroid_odyssey/agents_v1_gen/models/execution_status_response.py +0 -95
- asteroid_odyssey/agents_v1_gen/models/health_check200_response.py +0 -87
- asteroid_odyssey/agents_v1_gen/models/health_check500_response.py +0 -87
- asteroid_odyssey/agents_v1_gen/models/proxy_type.py +0 -38
- asteroid_odyssey/agents_v1_gen/models/status.py +0 -43
- asteroid_odyssey/agents_v1_gen/models/structured_agent_execution_request.py +0 -89
- asteroid_odyssey/agents_v1_gen/models/update_agent_profile_request.py +0 -126
- asteroid_odyssey/agents_v1_gen/rest.py +0 -257
- asteroid_odyssey/agents_v2_gen/__init__.py +0 -121
- asteroid_odyssey/agents_v2_gen/api/__init__.py +0 -7
- asteroid_odyssey/agents_v2_gen/api_response.py +0 -21
- asteroid_odyssey/agents_v2_gen/models/__init__.py +0 -102
- asteroid_odyssey/agents_v2_gen/py.typed +0 -0
- asteroid_odyssey/client.py +0 -1629
- asteroid_odyssey-1.3.13.dist-info/METADATA +0 -214
- asteroid_odyssey-1.3.13.dist-info/RECORD +0 -134
- /asteroid_odyssey/{agents_v1_gen/api_response.py → api_response.py} +0 -0
- /asteroid_odyssey/{agents_v2_gen/exceptions.py → exceptions.py} +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_execute_agent_response.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_agent_sort_field.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_action_name.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_generic_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_reasoning_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_step_completed_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_step_started_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_activity_user_message_received_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_awaiting_confirmation_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_cancel_reason.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_element_file_upload_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_ext_get_mail_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_file_list_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_file_stage_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_llm_call_purpose.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_nav_to_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_nav_to_started_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_node_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_paused_payload.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_rules_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_read_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_read_started_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scratchpad_write_started_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_hybrid_playwright_started_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_script_playwright_started_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_scriptpad_read_completed_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_sort_field.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_status.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_transition_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_update_type.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_user_messages_add_text_body.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_execution_util_get_datetime_started_details.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_files_temp_file.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_graph_models_nodes_properties_playwright_script_llm_var_type.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/agents_graph_models_transitions_transition_type.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_bad_request_error_body.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_error.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_forbidden_error_body.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_internal_server_error_body.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_not_found_error_body.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_os_error.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_sort_direction.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/common_unauthorized_error_body.py +0 -0
- /asteroid_odyssey/{agents_v2_gen/models → models}/version.py +0 -0
- /asteroid_odyssey/{agents_v1_gen/py.typed → py.typed} +0 -0
- {asteroid_odyssey-1.3.13.dist-info → asteroid_odyssey-1.6.1.dist-info}/WHEEL +0 -0
- {asteroid_odyssey-1.3.13.dist-info → asteroid_odyssey-1.6.1.dist-info}/top_level.txt +0 -0
asteroid_odyssey/client.py
DELETED
|
@@ -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
|
-
]
|