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