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] = []
auth
v1
activity_feed
agent_computers
agent_env_vars
agent_health_actions
agent_installations
agent_requests
agent_routine_runs
agent_routines
agent_sessions
agent_skills
agent_tools
agents
ai
artifacts
automation_runs
automations
bug_reports
config
custom_objects
event_subscription_deliveries
event_subscriptions
external_object_capabilities
external_objects
extractions
files
installation_sources
invites
knowledge_documents
knowledge_ingestions
knowledge_sources
kv
notification_preferences
notifications
orgs
private_service_definitions
private_service_enrollments
private_services
relays
sandboxes
scripts
slack_channel_bindings
solution_categories
solution_instances
solution_tags
solutions
ssh_keys
status
task_ownership_conversions
tasks
team_memberships
teams
thread_messages
threads
trajectories
users
work_items
workflows
oauth
refresh_token: str | None
102    @property
103    def refresh_token(self) -> str | None:
104        return self._refresh_token
def set_access_token(self, token: str):
106    def set_access_token(self, token: str):
107        self._access_token = token
108        self._http.set_access_token(token)
def set_refresh_token(self, token: str):
110    def set_refresh_token(self, token: str):
111        self._refresh_token = token
async def close(self):
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()
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] = []
auth
v1
activity_feed
agent_computers
agent_env_vars
agent_health_actions
agent_installations
agent_requests
agent_routine_runs
agent_routines
agent_sessions
agent_skills
agent_tools
agents
ai
artifacts
automation_runs
automations
bug_reports
config
custom_objects
event_subscription_deliveries
event_subscriptions
external_object_capabilities
external_objects
extractions
files
installation_sources
invites
knowledge_documents
knowledge_ingestions
knowledge_sources
kv
notification_preferences
notifications
orgs
private_service_definitions
private_service_enrollments
private_services
relays
sandboxes
scripts
slack_channel_bindings
solution_categories
solution_instances
solution_tags
solutions
ssh_keys
status
task_ownership_conversions
tasks
team_memberships
teams
thread_messages
threads
trajectories
users
work_items
workflows
oauth
refresh_token: str | None
342    @property
343    def refresh_token(self) -> str | None:
344        return self._refresh_token
def set_access_token(self, token: str):
346    def set_access_token(self, token: str):
347        self._http.set_access_token(token)
def set_refresh_token(self, token: str):
349    def set_refresh_token(self, token: str):
350        self._refresh_token = token
def close(self):
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()
@classmethod
def with_secret_key( cls, key: str, base_url: str | None = None) -> PlatformClient:
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