archastro.platform.client
1# Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. 2# This file is auto-generated by @archastro/sdk-generator. Do not edit. 3# Content hash: b950691a4ecf 4 5from urllib.parse import urlparse, urlunparse 6 7from archastro.phx_channel import Socket 8 9from .auth import AsyncAuthClient, AuthClient 10from .runtime.http_client import HttpClient, SyncHttpClient 11from .v1 import V1, AsyncV1 12 13 14class AsyncPlatformClient: 15 def __init__( 16 self, 17 *, 18 base_url: str = "https://platform.archastro.ai", 19 access_token: str | None = None, 20 get_access_token=None, 21 on_refresh_token=None, 22 path_prefix: str | None = None, 23 default_headers: dict[str, str] | None = None, 24 ): 25 self._base_url = base_url 26 self._access_token = access_token 27 self._get_access_token = get_access_token 28 self._default_headers = default_headers or {} 29 self._http = HttpClient( 30 base_url=base_url, 31 access_token=access_token, 32 get_access_token=get_access_token, 33 on_refresh_token=on_refresh_token, 34 path_prefix=path_prefix, 35 default_headers=default_headers, 36 ) 37 self.auth = AsyncAuthClient(self._http) 38 self.v1 = AsyncV1(self._http) 39 self.activity_feed = self.v1.activity_feed 40 self.agent_computers = self.v1.agent_computers 41 self.agent_env_vars = self.v1.agent_env_vars 42 self.agent_health_actions = self.v1.agent_health_actions 43 self.agent_installations = self.v1.agent_installations 44 self.agent_requests = self.v1.agent_requests 45 self.agent_routine_runs = self.v1.agent_routine_runs 46 self.agent_routines = self.v1.agent_routines 47 self.agent_sessions = self.v1.agent_sessions 48 self.agent_skills = self.v1.agent_skills 49 self.agent_tools = self.v1.agent_tools 50 self.agents = self.v1.agents 51 self.ai = self.v1.ai 52 self.artifacts = self.v1.artifacts 53 self.automation_runs = self.v1.automation_runs 54 self.automations = self.v1.automations 55 self.bug_reports = self.v1.bug_reports 56 self.config = self.v1.config 57 self.custom_objects = self.v1.custom_objects 58 self.event_subscription_deliveries = self.v1.event_subscription_deliveries 59 self.event_subscriptions = self.v1.event_subscriptions 60 self.external_object_capabilities = self.v1.external_object_capabilities 61 self.external_objects = self.v1.external_objects 62 self.extractions = self.v1.extractions 63 self.files = self.v1.files 64 self.installation_sources = self.v1.installation_sources 65 self.invites = self.v1.invites 66 self.knowledge_documents = self.v1.knowledge_documents 67 self.knowledge_ingestions = self.v1.knowledge_ingestions 68 self.knowledge_sources = self.v1.knowledge_sources 69 self.kv = self.v1.kv 70 self.notification_preferences = self.v1.notification_preferences 71 self.notifications = self.v1.notifications 72 self.orgs = self.v1.orgs 73 self.private_service_definitions = self.v1.private_service_definitions 74 self.private_service_enrollments = self.v1.private_service_enrollments 75 self.private_services = self.v1.private_services 76 self.relays = self.v1.relays 77 self.sandboxes = self.v1.sandboxes 78 self.scripts = self.v1.scripts 79 self.slack_channel_bindings = self.v1.slack_channel_bindings 80 self.solution_categories = self.v1.solution_categories 81 self.solution_instances = self.v1.solution_instances 82 self.solution_tags = self.v1.solution_tags 83 self.solutions = self.v1.solutions 84 self.ssh_keys = self.v1.ssh_keys 85 self.status = self.v1.status 86 self.task_ownership_conversions = self.v1.task_ownership_conversions 87 self.tasks = self.v1.tasks 88 self.team_memberships = self.v1.team_memberships 89 self.teams = self.v1.teams 90 self.thread_messages = self.v1.thread_messages 91 self.threads = self.v1.threads 92 self.trajectories = self.v1.trajectories 93 self.users = self.v1.users 94 self.work_items = self.v1.work_items 95 self.workflows = self.v1.workflows 96 self.oauth = self.v1.oauth 97 self._refresh_token: str | None = None 98 self._extra_http_clients: list[HttpClient] = [] 99 self._sockets: list[Socket] = [] 100 101 @property 102 def refresh_token(self) -> str | None: 103 return self._refresh_token 104 105 def set_access_token(self, token: str): 106 self._access_token = token 107 self._http.set_access_token(token) 108 109 def set_refresh_token(self, token: str): 110 self._refresh_token = token 111 112 async def __aenter__(self): 113 return self 114 115 async def __aexit__(self, exc_type, exc, tb): 116 await self.close() 117 118 async def close(self): 119 try: 120 try: 121 for socket in self._sockets: 122 await socket.disconnect() 123 finally: 124 self._sockets.clear() 125 await self._http.close() 126 finally: 127 for http in self._extra_http_clients: 128 await http.close() 129 self._extra_http_clients.clear() 130 131 def _current_access_token(self) -> str | None: 132 if self._get_access_token: 133 return self._get_access_token() 134 return self._access_token 135 136 def _api_key(self) -> str | None: 137 for key, value in self._default_headers.items(): 138 if key.lower() == "x-archastro-api-key".lower(): 139 return value 140 return None 141 142 def _socket_params(self, params: dict[str, str] | None = None) -> dict[str, str]: 143 socket_params: dict[str, str] = {} 144 api_key = self._api_key() 145 if api_key: 146 socket_params["api_key"] = api_key 147 token = self._current_access_token() 148 if token: 149 socket_params["token"] = token 150 if params: 151 socket_params.update(params) 152 return socket_params 153 154 def _default_websocket_url(self) -> str: 155 parsed = urlparse(self._base_url) 156 scheme = ( 157 "wss" 158 if parsed.scheme == "https" 159 else "ws" 160 if parsed.scheme == "http" 161 else parsed.scheme 162 ) 163 path = parsed.path.rstrip("/") + "/socket/api/websocket" 164 return urlunparse( 165 parsed._replace(scheme=scheme, path=path, params="", query="", fragment="") 166 ) 167 168 async def open_socket( 169 self, 170 *, 171 url: str | None = None, 172 params: dict[str, str] | None = None, 173 connect: bool = True, 174 heartbeat_interval: float = 30, 175 timeout: float = 10, 176 reconnect_backoff_ms: list[int] | None = None, 177 auto_reconnect: bool = True, 178 ) -> Socket: 179 socket_params = self._socket_params(params) 180 if connect and not socket_params.get("token"): 181 raise ValueError("AsyncPlatformClient.open_socket requires an access token") 182 socket = Socket( 183 url or self._default_websocket_url(), 184 params=socket_params, 185 heartbeat_interval=heartbeat_interval, 186 timeout=timeout, 187 reconnect_backoff_ms=reconnect_backoff_ms, 188 auto_reconnect=auto_reconnect, 189 ) 190 if connect: 191 await socket.connect() 192 if not socket.is_connected: 193 raise ConnectionError("WebSocket connection failed") 194 self._sockets.append(socket) 195 return socket 196 197 # ─── Factory constructors (generated from auth schemes) ─── 198 199 @classmethod 200 def with_secret_key(cls, key: str, base_url: str | None = None) -> "AsyncPlatformClient": 201 """Secret API key — full admin access, no user JWT required""" 202 kwargs = {} 203 if base_url: 204 kwargs["base_url"] = base_url 205 return cls(default_headers={"x-archastro-api-key": key}, **kwargs) 206 207 @classmethod 208 def with_token( 209 cls, api_key: str, access_token: str, base_url: str | None = None 210 ) -> "AsyncPlatformClient": 211 """Create a client with a publishable key and pre-existing access token.""" 212 kwargs = {} 213 if base_url: 214 kwargs["base_url"] = base_url 215 return cls( 216 access_token=access_token, default_headers={"x-archastro-api-key": api_key}, **kwargs 217 ) 218 219 @classmethod 220 async def with_credentials( 221 cls, api_key: str, email: str, password: str, base_url: str | None = None 222 ) -> "AsyncPlatformClient": 223 """Create a client by logging in with email/password""" 224 kwargs = {} 225 if base_url: 226 kwargs["base_url"] = base_url 227 client = cls(default_headers={"x-archastro-api-key": api_key}, **kwargs) 228 tokens = await client.auth.login(email, password) 229 if not tokens.access_token: 230 raise ValueError("Login did not return an access token") 231 client.set_access_token(tokens.access_token) 232 if tokens.refresh_token: 233 client.set_refresh_token(tokens.refresh_token) 234 refresh_http = HttpClient( 235 base_url=base_url or "https://platform.archastro.ai", 236 default_headers={"x-archastro-api-key": api_key}, 237 refresh_only=True, 238 ) 239 client._extra_http_clients.append(refresh_http) 240 refresh_auth = AsyncAuthClient(refresh_http) 241 242 async def _refresh() -> str: 243 rt = client.refresh_token 244 if not rt: 245 raise ValueError("No refresh token available") 246 refreshed = await refresh_auth.refresh(rt) 247 if not refreshed.access_token: 248 raise ValueError("Refresh did not return an access token") 249 client.set_access_token(refreshed.access_token) 250 if refreshed.refresh_token: 251 client.set_refresh_token(refreshed.refresh_token) 252 return refreshed.access_token 253 254 client._http.set_refresh_handler(_refresh) 255 return client 256 257 258class PlatformClient: 259 def __init__( 260 self, 261 *, 262 base_url: str = "https://platform.archastro.ai", 263 access_token: str | None = None, 264 get_access_token=None, 265 on_refresh_token=None, 266 path_prefix: str | None = None, 267 default_headers: dict[str, str] | None = None, 268 ): 269 self._closed = False 270 self._http = SyncHttpClient( 271 base_url=base_url, 272 access_token=access_token, 273 get_access_token=get_access_token, 274 on_refresh_token=on_refresh_token, 275 path_prefix=path_prefix, 276 default_headers=default_headers, 277 ) 278 self.auth = AuthClient(self._http) 279 self.v1 = V1(self._http) 280 self.activity_feed = self.v1.activity_feed 281 self.agent_computers = self.v1.agent_computers 282 self.agent_env_vars = self.v1.agent_env_vars 283 self.agent_health_actions = self.v1.agent_health_actions 284 self.agent_installations = self.v1.agent_installations 285 self.agent_requests = self.v1.agent_requests 286 self.agent_routine_runs = self.v1.agent_routine_runs 287 self.agent_routines = self.v1.agent_routines 288 self.agent_sessions = self.v1.agent_sessions 289 self.agent_skills = self.v1.agent_skills 290 self.agent_tools = self.v1.agent_tools 291 self.agents = self.v1.agents 292 self.ai = self.v1.ai 293 self.artifacts = self.v1.artifacts 294 self.automation_runs = self.v1.automation_runs 295 self.automations = self.v1.automations 296 self.bug_reports = self.v1.bug_reports 297 self.config = self.v1.config 298 self.custom_objects = self.v1.custom_objects 299 self.event_subscription_deliveries = self.v1.event_subscription_deliveries 300 self.event_subscriptions = self.v1.event_subscriptions 301 self.external_object_capabilities = self.v1.external_object_capabilities 302 self.external_objects = self.v1.external_objects 303 self.extractions = self.v1.extractions 304 self.files = self.v1.files 305 self.installation_sources = self.v1.installation_sources 306 self.invites = self.v1.invites 307 self.knowledge_documents = self.v1.knowledge_documents 308 self.knowledge_ingestions = self.v1.knowledge_ingestions 309 self.knowledge_sources = self.v1.knowledge_sources 310 self.kv = self.v1.kv 311 self.notification_preferences = self.v1.notification_preferences 312 self.notifications = self.v1.notifications 313 self.orgs = self.v1.orgs 314 self.private_service_definitions = self.v1.private_service_definitions 315 self.private_service_enrollments = self.v1.private_service_enrollments 316 self.private_services = self.v1.private_services 317 self.relays = self.v1.relays 318 self.sandboxes = self.v1.sandboxes 319 self.scripts = self.v1.scripts 320 self.slack_channel_bindings = self.v1.slack_channel_bindings 321 self.solution_categories = self.v1.solution_categories 322 self.solution_instances = self.v1.solution_instances 323 self.solution_tags = self.v1.solution_tags 324 self.solutions = self.v1.solutions 325 self.ssh_keys = self.v1.ssh_keys 326 self.status = self.v1.status 327 self.task_ownership_conversions = self.v1.task_ownership_conversions 328 self.tasks = self.v1.tasks 329 self.team_memberships = self.v1.team_memberships 330 self.teams = self.v1.teams 331 self.thread_messages = self.v1.thread_messages 332 self.threads = self.v1.threads 333 self.trajectories = self.v1.trajectories 334 self.users = self.v1.users 335 self.work_items = self.v1.work_items 336 self.workflows = self.v1.workflows 337 self.oauth = self.v1.oauth 338 self._refresh_token: str | None = None 339 self._extra_http_clients: list[SyncHttpClient] = [] 340 341 @property 342 def refresh_token(self) -> str | None: 343 return self._refresh_token 344 345 def set_access_token(self, token: str): 346 self._http.set_access_token(token) 347 348 def set_refresh_token(self, token: str): 349 self._refresh_token = token 350 351 def __enter__(self): 352 return self 353 354 def __exit__(self, exc_type, exc, tb): 355 self.close() 356 357 def close(self): 358 if self._closed: 359 return 360 self._closed = True 361 try: 362 self._http.close() 363 finally: 364 for http in self._extra_http_clients: 365 http.close() 366 self._extra_http_clients.clear() 367 368 # ─── Factory constructors (generated from auth schemes) ─── 369 370 @classmethod 371 def with_secret_key(cls, key: str, base_url: str | None = None) -> "PlatformClient": 372 """Secret API key — full admin access, no user JWT required""" 373 kwargs = {} 374 if base_url: 375 kwargs["base_url"] = base_url 376 return cls(default_headers={"x-archastro-api-key": key}, **kwargs) 377 378 @classmethod 379 def with_token( 380 cls, api_key: str, access_token: str, base_url: str | None = None 381 ) -> "PlatformClient": 382 """Create a client with a publishable key and pre-existing access token.""" 383 kwargs = {} 384 if base_url: 385 kwargs["base_url"] = base_url 386 return cls( 387 access_token=access_token, default_headers={"x-archastro-api-key": api_key}, **kwargs 388 ) 389 390 @classmethod 391 def with_credentials( 392 cls, api_key: str, email: str, password: str, base_url: str | None = None 393 ) -> "PlatformClient": 394 kwargs = {} 395 if base_url: 396 kwargs["base_url"] = base_url 397 client = cls(default_headers={"x-archastro-api-key": api_key}, **kwargs) 398 tokens = client.auth.login(email, password) 399 if not tokens.access_token: 400 raise ValueError("Login did not return an access token") 401 client.set_access_token(tokens.access_token) 402 if tokens.refresh_token: 403 client.set_refresh_token(tokens.refresh_token) 404 refresh_http = SyncHttpClient( 405 base_url=base_url or "https://platform.archastro.ai", 406 default_headers={"x-archastro-api-key": api_key}, 407 refresh_only=True, 408 ) 409 client._extra_http_clients.append(refresh_http) 410 refresh_auth = AuthClient(refresh_http) 411 412 def _refresh() -> str: 413 rt = client.refresh_token 414 if not rt: 415 raise ValueError("No refresh token available") 416 refreshed = refresh_auth.refresh(rt) 417 if not refreshed.access_token: 418 raise ValueError("Refresh did not return an access token") 419 client.set_access_token(refreshed.access_token) 420 if refreshed.refresh_token: 421 client.set_refresh_token(refreshed.refresh_token) 422 return refreshed.access_token 423 424 client._http.set_refresh_handler(_refresh) 425 return client
class
AsyncPlatformClient:
15class AsyncPlatformClient: 16 def __init__( 17 self, 18 *, 19 base_url: str = "https://platform.archastro.ai", 20 access_token: str | None = None, 21 get_access_token=None, 22 on_refresh_token=None, 23 path_prefix: str | None = None, 24 default_headers: dict[str, str] | None = None, 25 ): 26 self._base_url = base_url 27 self._access_token = access_token 28 self._get_access_token = get_access_token 29 self._default_headers = default_headers or {} 30 self._http = HttpClient( 31 base_url=base_url, 32 access_token=access_token, 33 get_access_token=get_access_token, 34 on_refresh_token=on_refresh_token, 35 path_prefix=path_prefix, 36 default_headers=default_headers, 37 ) 38 self.auth = AsyncAuthClient(self._http) 39 self.v1 = AsyncV1(self._http) 40 self.activity_feed = self.v1.activity_feed 41 self.agent_computers = self.v1.agent_computers 42 self.agent_env_vars = self.v1.agent_env_vars 43 self.agent_health_actions = self.v1.agent_health_actions 44 self.agent_installations = self.v1.agent_installations 45 self.agent_requests = self.v1.agent_requests 46 self.agent_routine_runs = self.v1.agent_routine_runs 47 self.agent_routines = self.v1.agent_routines 48 self.agent_sessions = self.v1.agent_sessions 49 self.agent_skills = self.v1.agent_skills 50 self.agent_tools = self.v1.agent_tools 51 self.agents = self.v1.agents 52 self.ai = self.v1.ai 53 self.artifacts = self.v1.artifacts 54 self.automation_runs = self.v1.automation_runs 55 self.automations = self.v1.automations 56 self.bug_reports = self.v1.bug_reports 57 self.config = self.v1.config 58 self.custom_objects = self.v1.custom_objects 59 self.event_subscription_deliveries = self.v1.event_subscription_deliveries 60 self.event_subscriptions = self.v1.event_subscriptions 61 self.external_object_capabilities = self.v1.external_object_capabilities 62 self.external_objects = self.v1.external_objects 63 self.extractions = self.v1.extractions 64 self.files = self.v1.files 65 self.installation_sources = self.v1.installation_sources 66 self.invites = self.v1.invites 67 self.knowledge_documents = self.v1.knowledge_documents 68 self.knowledge_ingestions = self.v1.knowledge_ingestions 69 self.knowledge_sources = self.v1.knowledge_sources 70 self.kv = self.v1.kv 71 self.notification_preferences = self.v1.notification_preferences 72 self.notifications = self.v1.notifications 73 self.orgs = self.v1.orgs 74 self.private_service_definitions = self.v1.private_service_definitions 75 self.private_service_enrollments = self.v1.private_service_enrollments 76 self.private_services = self.v1.private_services 77 self.relays = self.v1.relays 78 self.sandboxes = self.v1.sandboxes 79 self.scripts = self.v1.scripts 80 self.slack_channel_bindings = self.v1.slack_channel_bindings 81 self.solution_categories = self.v1.solution_categories 82 self.solution_instances = self.v1.solution_instances 83 self.solution_tags = self.v1.solution_tags 84 self.solutions = self.v1.solutions 85 self.ssh_keys = self.v1.ssh_keys 86 self.status = self.v1.status 87 self.task_ownership_conversions = self.v1.task_ownership_conversions 88 self.tasks = self.v1.tasks 89 self.team_memberships = self.v1.team_memberships 90 self.teams = self.v1.teams 91 self.thread_messages = self.v1.thread_messages 92 self.threads = self.v1.threads 93 self.trajectories = self.v1.trajectories 94 self.users = self.v1.users 95 self.work_items = self.v1.work_items 96 self.workflows = self.v1.workflows 97 self.oauth = self.v1.oauth 98 self._refresh_token: str | None = None 99 self._extra_http_clients: list[HttpClient] = [] 100 self._sockets: list[Socket] = [] 101 102 @property 103 def refresh_token(self) -> str | None: 104 return self._refresh_token 105 106 def set_access_token(self, token: str): 107 self._access_token = token 108 self._http.set_access_token(token) 109 110 def set_refresh_token(self, token: str): 111 self._refresh_token = token 112 113 async def __aenter__(self): 114 return self 115 116 async def __aexit__(self, exc_type, exc, tb): 117 await self.close() 118 119 async def close(self): 120 try: 121 try: 122 for socket in self._sockets: 123 await socket.disconnect() 124 finally: 125 self._sockets.clear() 126 await self._http.close() 127 finally: 128 for http in self._extra_http_clients: 129 await http.close() 130 self._extra_http_clients.clear() 131 132 def _current_access_token(self) -> str | None: 133 if self._get_access_token: 134 return self._get_access_token() 135 return self._access_token 136 137 def _api_key(self) -> str | None: 138 for key, value in self._default_headers.items(): 139 if key.lower() == "x-archastro-api-key".lower(): 140 return value 141 return None 142 143 def _socket_params(self, params: dict[str, str] | None = None) -> dict[str, str]: 144 socket_params: dict[str, str] = {} 145 api_key = self._api_key() 146 if api_key: 147 socket_params["api_key"] = api_key 148 token = self._current_access_token() 149 if token: 150 socket_params["token"] = token 151 if params: 152 socket_params.update(params) 153 return socket_params 154 155 def _default_websocket_url(self) -> str: 156 parsed = urlparse(self._base_url) 157 scheme = ( 158 "wss" 159 if parsed.scheme == "https" 160 else "ws" 161 if parsed.scheme == "http" 162 else parsed.scheme 163 ) 164 path = parsed.path.rstrip("/") + "/socket/api/websocket" 165 return urlunparse( 166 parsed._replace(scheme=scheme, path=path, params="", query="", fragment="") 167 ) 168 169 async def open_socket( 170 self, 171 *, 172 url: str | None = None, 173 params: dict[str, str] | None = None, 174 connect: bool = True, 175 heartbeat_interval: float = 30, 176 timeout: float = 10, 177 reconnect_backoff_ms: list[int] | None = None, 178 auto_reconnect: bool = True, 179 ) -> Socket: 180 socket_params = self._socket_params(params) 181 if connect and not socket_params.get("token"): 182 raise ValueError("AsyncPlatformClient.open_socket requires an access token") 183 socket = Socket( 184 url or self._default_websocket_url(), 185 params=socket_params, 186 heartbeat_interval=heartbeat_interval, 187 timeout=timeout, 188 reconnect_backoff_ms=reconnect_backoff_ms, 189 auto_reconnect=auto_reconnect, 190 ) 191 if connect: 192 await socket.connect() 193 if not socket.is_connected: 194 raise ConnectionError("WebSocket connection failed") 195 self._sockets.append(socket) 196 return socket 197 198 # ─── Factory constructors (generated from auth schemes) ─── 199 200 @classmethod 201 def with_secret_key(cls, key: str, base_url: str | None = None) -> "AsyncPlatformClient": 202 """Secret API key — full admin access, no user JWT required""" 203 kwargs = {} 204 if base_url: 205 kwargs["base_url"] = base_url 206 return cls(default_headers={"x-archastro-api-key": key}, **kwargs) 207 208 @classmethod 209 def with_token( 210 cls, api_key: str, access_token: str, base_url: str | None = None 211 ) -> "AsyncPlatformClient": 212 """Create a client with a publishable key and pre-existing access token.""" 213 kwargs = {} 214 if base_url: 215 kwargs["base_url"] = base_url 216 return cls( 217 access_token=access_token, default_headers={"x-archastro-api-key": api_key}, **kwargs 218 ) 219 220 @classmethod 221 async def with_credentials( 222 cls, api_key: str, email: str, password: str, base_url: str | None = None 223 ) -> "AsyncPlatformClient": 224 """Create a client by logging in with email/password""" 225 kwargs = {} 226 if base_url: 227 kwargs["base_url"] = base_url 228 client = cls(default_headers={"x-archastro-api-key": api_key}, **kwargs) 229 tokens = await client.auth.login(email, password) 230 if not tokens.access_token: 231 raise ValueError("Login did not return an access token") 232 client.set_access_token(tokens.access_token) 233 if tokens.refresh_token: 234 client.set_refresh_token(tokens.refresh_token) 235 refresh_http = HttpClient( 236 base_url=base_url or "https://platform.archastro.ai", 237 default_headers={"x-archastro-api-key": api_key}, 238 refresh_only=True, 239 ) 240 client._extra_http_clients.append(refresh_http) 241 refresh_auth = AsyncAuthClient(refresh_http) 242 243 async def _refresh() -> str: 244 rt = client.refresh_token 245 if not rt: 246 raise ValueError("No refresh token available") 247 refreshed = await refresh_auth.refresh(rt) 248 if not refreshed.access_token: 249 raise ValueError("Refresh did not return an access token") 250 client.set_access_token(refreshed.access_token) 251 if refreshed.refresh_token: 252 client.set_refresh_token(refreshed.refresh_token) 253 return refreshed.access_token 254 255 client._http.set_refresh_handler(_refresh) 256 return client
AsyncPlatformClient( *, base_url: str = 'https://platform.archastro.ai', access_token: str | None = None, get_access_token=None, on_refresh_token=None, path_prefix: str | None = None, default_headers: dict[str, str] | None = None)
16 def __init__( 17 self, 18 *, 19 base_url: str = "https://platform.archastro.ai", 20 access_token: str | None = None, 21 get_access_token=None, 22 on_refresh_token=None, 23 path_prefix: str | None = None, 24 default_headers: dict[str, str] | None = None, 25 ): 26 self._base_url = base_url 27 self._access_token = access_token 28 self._get_access_token = get_access_token 29 self._default_headers = default_headers or {} 30 self._http = HttpClient( 31 base_url=base_url, 32 access_token=access_token, 33 get_access_token=get_access_token, 34 on_refresh_token=on_refresh_token, 35 path_prefix=path_prefix, 36 default_headers=default_headers, 37 ) 38 self.auth = AsyncAuthClient(self._http) 39 self.v1 = AsyncV1(self._http) 40 self.activity_feed = self.v1.activity_feed 41 self.agent_computers = self.v1.agent_computers 42 self.agent_env_vars = self.v1.agent_env_vars 43 self.agent_health_actions = self.v1.agent_health_actions 44 self.agent_installations = self.v1.agent_installations 45 self.agent_requests = self.v1.agent_requests 46 self.agent_routine_runs = self.v1.agent_routine_runs 47 self.agent_routines = self.v1.agent_routines 48 self.agent_sessions = self.v1.agent_sessions 49 self.agent_skills = self.v1.agent_skills 50 self.agent_tools = self.v1.agent_tools 51 self.agents = self.v1.agents 52 self.ai = self.v1.ai 53 self.artifacts = self.v1.artifacts 54 self.automation_runs = self.v1.automation_runs 55 self.automations = self.v1.automations 56 self.bug_reports = self.v1.bug_reports 57 self.config = self.v1.config 58 self.custom_objects = self.v1.custom_objects 59 self.event_subscription_deliveries = self.v1.event_subscription_deliveries 60 self.event_subscriptions = self.v1.event_subscriptions 61 self.external_object_capabilities = self.v1.external_object_capabilities 62 self.external_objects = self.v1.external_objects 63 self.extractions = self.v1.extractions 64 self.files = self.v1.files 65 self.installation_sources = self.v1.installation_sources 66 self.invites = self.v1.invites 67 self.knowledge_documents = self.v1.knowledge_documents 68 self.knowledge_ingestions = self.v1.knowledge_ingestions 69 self.knowledge_sources = self.v1.knowledge_sources 70 self.kv = self.v1.kv 71 self.notification_preferences = self.v1.notification_preferences 72 self.notifications = self.v1.notifications 73 self.orgs = self.v1.orgs 74 self.private_service_definitions = self.v1.private_service_definitions 75 self.private_service_enrollments = self.v1.private_service_enrollments 76 self.private_services = self.v1.private_services 77 self.relays = self.v1.relays 78 self.sandboxes = self.v1.sandboxes 79 self.scripts = self.v1.scripts 80 self.slack_channel_bindings = self.v1.slack_channel_bindings 81 self.solution_categories = self.v1.solution_categories 82 self.solution_instances = self.v1.solution_instances 83 self.solution_tags = self.v1.solution_tags 84 self.solutions = self.v1.solutions 85 self.ssh_keys = self.v1.ssh_keys 86 self.status = self.v1.status 87 self.task_ownership_conversions = self.v1.task_ownership_conversions 88 self.tasks = self.v1.tasks 89 self.team_memberships = self.v1.team_memberships 90 self.teams = self.v1.teams 91 self.thread_messages = self.v1.thread_messages 92 self.threads = self.v1.threads 93 self.trajectories = self.v1.trajectories 94 self.users = self.v1.users 95 self.work_items = self.v1.work_items 96 self.workflows = self.v1.workflows 97 self.oauth = self.v1.oauth 98 self._refresh_token: str | None = None 99 self._extra_http_clients: list[HttpClient] = [] 100 self._sockets: list[Socket] = []
async def
open_socket( self, *, url: str | None = None, params: dict[str, str] | None = None, connect: bool = True, heartbeat_interval: float = 30, timeout: float = 10, reconnect_backoff_ms: list[int] | None = None, auto_reconnect: bool = True) -> archastro.phx_channel.Socket:
169 async def open_socket( 170 self, 171 *, 172 url: str | None = None, 173 params: dict[str, str] | None = None, 174 connect: bool = True, 175 heartbeat_interval: float = 30, 176 timeout: float = 10, 177 reconnect_backoff_ms: list[int] | None = None, 178 auto_reconnect: bool = True, 179 ) -> Socket: 180 socket_params = self._socket_params(params) 181 if connect and not socket_params.get("token"): 182 raise ValueError("AsyncPlatformClient.open_socket requires an access token") 183 socket = Socket( 184 url or self._default_websocket_url(), 185 params=socket_params, 186 heartbeat_interval=heartbeat_interval, 187 timeout=timeout, 188 reconnect_backoff_ms=reconnect_backoff_ms, 189 auto_reconnect=auto_reconnect, 190 ) 191 if connect: 192 await socket.connect() 193 if not socket.is_connected: 194 raise ConnectionError("WebSocket connection failed") 195 self._sockets.append(socket) 196 return socket
@classmethod
def
with_secret_key( cls, key: str, base_url: str | None = None) -> AsyncPlatformClient:
200 @classmethod 201 def with_secret_key(cls, key: str, base_url: str | None = None) -> "AsyncPlatformClient": 202 """Secret API key — full admin access, no user JWT required""" 203 kwargs = {} 204 if base_url: 205 kwargs["base_url"] = base_url 206 return cls(default_headers={"x-archastro-api-key": key}, **kwargs)
Secret API key — full admin access, no user JWT required
@classmethod
def
with_token( cls, api_key: str, access_token: str, base_url: str | None = None) -> AsyncPlatformClient:
208 @classmethod 209 def with_token( 210 cls, api_key: str, access_token: str, base_url: str | None = None 211 ) -> "AsyncPlatformClient": 212 """Create a client with a publishable key and pre-existing access token.""" 213 kwargs = {} 214 if base_url: 215 kwargs["base_url"] = base_url 216 return cls( 217 access_token=access_token, default_headers={"x-archastro-api-key": api_key}, **kwargs 218 )
Create a client with a publishable key and pre-existing access token.
@classmethod
async def
with_credentials( cls, api_key: str, email: str, password: str, base_url: str | None = None) -> AsyncPlatformClient:
220 @classmethod 221 async def with_credentials( 222 cls, api_key: str, email: str, password: str, base_url: str | None = None 223 ) -> "AsyncPlatformClient": 224 """Create a client by logging in with email/password""" 225 kwargs = {} 226 if base_url: 227 kwargs["base_url"] = base_url 228 client = cls(default_headers={"x-archastro-api-key": api_key}, **kwargs) 229 tokens = await client.auth.login(email, password) 230 if not tokens.access_token: 231 raise ValueError("Login did not return an access token") 232 client.set_access_token(tokens.access_token) 233 if tokens.refresh_token: 234 client.set_refresh_token(tokens.refresh_token) 235 refresh_http = HttpClient( 236 base_url=base_url or "https://platform.archastro.ai", 237 default_headers={"x-archastro-api-key": api_key}, 238 refresh_only=True, 239 ) 240 client._extra_http_clients.append(refresh_http) 241 refresh_auth = AsyncAuthClient(refresh_http) 242 243 async def _refresh() -> str: 244 rt = client.refresh_token 245 if not rt: 246 raise ValueError("No refresh token available") 247 refreshed = await refresh_auth.refresh(rt) 248 if not refreshed.access_token: 249 raise ValueError("Refresh did not return an access token") 250 client.set_access_token(refreshed.access_token) 251 if refreshed.refresh_token: 252 client.set_refresh_token(refreshed.refresh_token) 253 return refreshed.access_token 254 255 client._http.set_refresh_handler(_refresh) 256 return client
Create a client by logging in with email/password
class
PlatformClient:
259class PlatformClient: 260 def __init__( 261 self, 262 *, 263 base_url: str = "https://platform.archastro.ai", 264 access_token: str | None = None, 265 get_access_token=None, 266 on_refresh_token=None, 267 path_prefix: str | None = None, 268 default_headers: dict[str, str] | None = None, 269 ): 270 self._closed = False 271 self._http = SyncHttpClient( 272 base_url=base_url, 273 access_token=access_token, 274 get_access_token=get_access_token, 275 on_refresh_token=on_refresh_token, 276 path_prefix=path_prefix, 277 default_headers=default_headers, 278 ) 279 self.auth = AuthClient(self._http) 280 self.v1 = V1(self._http) 281 self.activity_feed = self.v1.activity_feed 282 self.agent_computers = self.v1.agent_computers 283 self.agent_env_vars = self.v1.agent_env_vars 284 self.agent_health_actions = self.v1.agent_health_actions 285 self.agent_installations = self.v1.agent_installations 286 self.agent_requests = self.v1.agent_requests 287 self.agent_routine_runs = self.v1.agent_routine_runs 288 self.agent_routines = self.v1.agent_routines 289 self.agent_sessions = self.v1.agent_sessions 290 self.agent_skills = self.v1.agent_skills 291 self.agent_tools = self.v1.agent_tools 292 self.agents = self.v1.agents 293 self.ai = self.v1.ai 294 self.artifacts = self.v1.artifacts 295 self.automation_runs = self.v1.automation_runs 296 self.automations = self.v1.automations 297 self.bug_reports = self.v1.bug_reports 298 self.config = self.v1.config 299 self.custom_objects = self.v1.custom_objects 300 self.event_subscription_deliveries = self.v1.event_subscription_deliveries 301 self.event_subscriptions = self.v1.event_subscriptions 302 self.external_object_capabilities = self.v1.external_object_capabilities 303 self.external_objects = self.v1.external_objects 304 self.extractions = self.v1.extractions 305 self.files = self.v1.files 306 self.installation_sources = self.v1.installation_sources 307 self.invites = self.v1.invites 308 self.knowledge_documents = self.v1.knowledge_documents 309 self.knowledge_ingestions = self.v1.knowledge_ingestions 310 self.knowledge_sources = self.v1.knowledge_sources 311 self.kv = self.v1.kv 312 self.notification_preferences = self.v1.notification_preferences 313 self.notifications = self.v1.notifications 314 self.orgs = self.v1.orgs 315 self.private_service_definitions = self.v1.private_service_definitions 316 self.private_service_enrollments = self.v1.private_service_enrollments 317 self.private_services = self.v1.private_services 318 self.relays = self.v1.relays 319 self.sandboxes = self.v1.sandboxes 320 self.scripts = self.v1.scripts 321 self.slack_channel_bindings = self.v1.slack_channel_bindings 322 self.solution_categories = self.v1.solution_categories 323 self.solution_instances = self.v1.solution_instances 324 self.solution_tags = self.v1.solution_tags 325 self.solutions = self.v1.solutions 326 self.ssh_keys = self.v1.ssh_keys 327 self.status = self.v1.status 328 self.task_ownership_conversions = self.v1.task_ownership_conversions 329 self.tasks = self.v1.tasks 330 self.team_memberships = self.v1.team_memberships 331 self.teams = self.v1.teams 332 self.thread_messages = self.v1.thread_messages 333 self.threads = self.v1.threads 334 self.trajectories = self.v1.trajectories 335 self.users = self.v1.users 336 self.work_items = self.v1.work_items 337 self.workflows = self.v1.workflows 338 self.oauth = self.v1.oauth 339 self._refresh_token: str | None = None 340 self._extra_http_clients: list[SyncHttpClient] = [] 341 342 @property 343 def refresh_token(self) -> str | None: 344 return self._refresh_token 345 346 def set_access_token(self, token: str): 347 self._http.set_access_token(token) 348 349 def set_refresh_token(self, token: str): 350 self._refresh_token = token 351 352 def __enter__(self): 353 return self 354 355 def __exit__(self, exc_type, exc, tb): 356 self.close() 357 358 def close(self): 359 if self._closed: 360 return 361 self._closed = True 362 try: 363 self._http.close() 364 finally: 365 for http in self._extra_http_clients: 366 http.close() 367 self._extra_http_clients.clear() 368 369 # ─── Factory constructors (generated from auth schemes) ─── 370 371 @classmethod 372 def with_secret_key(cls, key: str, base_url: str | None = None) -> "PlatformClient": 373 """Secret API key — full admin access, no user JWT required""" 374 kwargs = {} 375 if base_url: 376 kwargs["base_url"] = base_url 377 return cls(default_headers={"x-archastro-api-key": key}, **kwargs) 378 379 @classmethod 380 def with_token( 381 cls, api_key: str, access_token: str, base_url: str | None = None 382 ) -> "PlatformClient": 383 """Create a client with a publishable key and pre-existing access token.""" 384 kwargs = {} 385 if base_url: 386 kwargs["base_url"] = base_url 387 return cls( 388 access_token=access_token, default_headers={"x-archastro-api-key": api_key}, **kwargs 389 ) 390 391 @classmethod 392 def with_credentials( 393 cls, api_key: str, email: str, password: str, base_url: str | None = None 394 ) -> "PlatformClient": 395 kwargs = {} 396 if base_url: 397 kwargs["base_url"] = base_url 398 client = cls(default_headers={"x-archastro-api-key": api_key}, **kwargs) 399 tokens = client.auth.login(email, password) 400 if not tokens.access_token: 401 raise ValueError("Login did not return an access token") 402 client.set_access_token(tokens.access_token) 403 if tokens.refresh_token: 404 client.set_refresh_token(tokens.refresh_token) 405 refresh_http = SyncHttpClient( 406 base_url=base_url or "https://platform.archastro.ai", 407 default_headers={"x-archastro-api-key": api_key}, 408 refresh_only=True, 409 ) 410 client._extra_http_clients.append(refresh_http) 411 refresh_auth = AuthClient(refresh_http) 412 413 def _refresh() -> str: 414 rt = client.refresh_token 415 if not rt: 416 raise ValueError("No refresh token available") 417 refreshed = refresh_auth.refresh(rt) 418 if not refreshed.access_token: 419 raise ValueError("Refresh did not return an access token") 420 client.set_access_token(refreshed.access_token) 421 if refreshed.refresh_token: 422 client.set_refresh_token(refreshed.refresh_token) 423 return refreshed.access_token 424 425 client._http.set_refresh_handler(_refresh) 426 return client
PlatformClient( *, base_url: str = 'https://platform.archastro.ai', access_token: str | None = None, get_access_token=None, on_refresh_token=None, path_prefix: str | None = None, default_headers: dict[str, str] | None = None)
260 def __init__( 261 self, 262 *, 263 base_url: str = "https://platform.archastro.ai", 264 access_token: str | None = None, 265 get_access_token=None, 266 on_refresh_token=None, 267 path_prefix: str | None = None, 268 default_headers: dict[str, str] | None = None, 269 ): 270 self._closed = False 271 self._http = SyncHttpClient( 272 base_url=base_url, 273 access_token=access_token, 274 get_access_token=get_access_token, 275 on_refresh_token=on_refresh_token, 276 path_prefix=path_prefix, 277 default_headers=default_headers, 278 ) 279 self.auth = AuthClient(self._http) 280 self.v1 = V1(self._http) 281 self.activity_feed = self.v1.activity_feed 282 self.agent_computers = self.v1.agent_computers 283 self.agent_env_vars = self.v1.agent_env_vars 284 self.agent_health_actions = self.v1.agent_health_actions 285 self.agent_installations = self.v1.agent_installations 286 self.agent_requests = self.v1.agent_requests 287 self.agent_routine_runs = self.v1.agent_routine_runs 288 self.agent_routines = self.v1.agent_routines 289 self.agent_sessions = self.v1.agent_sessions 290 self.agent_skills = self.v1.agent_skills 291 self.agent_tools = self.v1.agent_tools 292 self.agents = self.v1.agents 293 self.ai = self.v1.ai 294 self.artifacts = self.v1.artifacts 295 self.automation_runs = self.v1.automation_runs 296 self.automations = self.v1.automations 297 self.bug_reports = self.v1.bug_reports 298 self.config = self.v1.config 299 self.custom_objects = self.v1.custom_objects 300 self.event_subscription_deliveries = self.v1.event_subscription_deliveries 301 self.event_subscriptions = self.v1.event_subscriptions 302 self.external_object_capabilities = self.v1.external_object_capabilities 303 self.external_objects = self.v1.external_objects 304 self.extractions = self.v1.extractions 305 self.files = self.v1.files 306 self.installation_sources = self.v1.installation_sources 307 self.invites = self.v1.invites 308 self.knowledge_documents = self.v1.knowledge_documents 309 self.knowledge_ingestions = self.v1.knowledge_ingestions 310 self.knowledge_sources = self.v1.knowledge_sources 311 self.kv = self.v1.kv 312 self.notification_preferences = self.v1.notification_preferences 313 self.notifications = self.v1.notifications 314 self.orgs = self.v1.orgs 315 self.private_service_definitions = self.v1.private_service_definitions 316 self.private_service_enrollments = self.v1.private_service_enrollments 317 self.private_services = self.v1.private_services 318 self.relays = self.v1.relays 319 self.sandboxes = self.v1.sandboxes 320 self.scripts = self.v1.scripts 321 self.slack_channel_bindings = self.v1.slack_channel_bindings 322 self.solution_categories = self.v1.solution_categories 323 self.solution_instances = self.v1.solution_instances 324 self.solution_tags = self.v1.solution_tags 325 self.solutions = self.v1.solutions 326 self.ssh_keys = self.v1.ssh_keys 327 self.status = self.v1.status 328 self.task_ownership_conversions = self.v1.task_ownership_conversions 329 self.tasks = self.v1.tasks 330 self.team_memberships = self.v1.team_memberships 331 self.teams = self.v1.teams 332 self.thread_messages = self.v1.thread_messages 333 self.threads = self.v1.threads 334 self.trajectories = self.v1.trajectories 335 self.users = self.v1.users 336 self.work_items = self.v1.work_items 337 self.workflows = self.v1.workflows 338 self.oauth = self.v1.oauth 339 self._refresh_token: str | None = None 340 self._extra_http_clients: list[SyncHttpClient] = []
371 @classmethod 372 def with_secret_key(cls, key: str, base_url: str | None = None) -> "PlatformClient": 373 """Secret API key — full admin access, no user JWT required""" 374 kwargs = {} 375 if base_url: 376 kwargs["base_url"] = base_url 377 return cls(default_headers={"x-archastro-api-key": key}, **kwargs)
Secret API key — full admin access, no user JWT required
@classmethod
def
with_token( cls, api_key: str, access_token: str, base_url: str | None = None) -> PlatformClient:
379 @classmethod 380 def with_token( 381 cls, api_key: str, access_token: str, base_url: str | None = None 382 ) -> "PlatformClient": 383 """Create a client with a publishable key and pre-existing access token.""" 384 kwargs = {} 385 if base_url: 386 kwargs["base_url"] = base_url 387 return cls( 388 access_token=access_token, default_headers={"x-archastro-api-key": api_key}, **kwargs 389 )
Create a client with a publishable key and pre-existing access token.
@classmethod
def
with_credentials( cls, api_key: str, email: str, password: str, base_url: str | None = None) -> PlatformClient:
391 @classmethod 392 def with_credentials( 393 cls, api_key: str, email: str, password: str, base_url: str | None = None 394 ) -> "PlatformClient": 395 kwargs = {} 396 if base_url: 397 kwargs["base_url"] = base_url 398 client = cls(default_headers={"x-archastro-api-key": api_key}, **kwargs) 399 tokens = client.auth.login(email, password) 400 if not tokens.access_token: 401 raise ValueError("Login did not return an access token") 402 client.set_access_token(tokens.access_token) 403 if tokens.refresh_token: 404 client.set_refresh_token(tokens.refresh_token) 405 refresh_http = SyncHttpClient( 406 base_url=base_url or "https://platform.archastro.ai", 407 default_headers={"x-archastro-api-key": api_key}, 408 refresh_only=True, 409 ) 410 client._extra_http_clients.append(refresh_http) 411 refresh_auth = AuthClient(refresh_http) 412 413 def _refresh() -> str: 414 rt = client.refresh_token 415 if not rt: 416 raise ValueError("No refresh token available") 417 refreshed = refresh_auth.refresh(rt) 418 if not refreshed.access_token: 419 raise ValueError("Refresh did not return an access token") 420 client.set_access_token(refreshed.access_token) 421 if refreshed.refresh_token: 422 client.set_refresh_token(refreshed.refresh_token) 423 return refreshed.access_token 424 425 client._http.set_refresh_handler(_refresh) 426 return client