airbyte.agents.workspaces

Airbyte Agents workspaces.

⚠️ Experimental Interface

The Airbyte Agents Python interfaces are experimental. Class names, method signatures, and result models may change or be removed without notice between minor versions of PyAirbyte. Pin an exact PyAirbyte version if you depend on them.

  1# Copyright (c) 2026 Airbyte, Inc., all rights reserved.
  2"""Airbyte Agents workspaces.
  3
  4> ## ⚠️ Experimental Interface
  5>
  6> **The Airbyte Agents Python interfaces are experimental.** Class names, method signatures,
  7> and result models may change or be removed without notice between minor versions of
  8> PyAirbyte. Pin an exact PyAirbyte version if you depend on them.
  9"""
 10
 11from __future__ import annotations
 12
 13from typing import TYPE_CHECKING
 14
 15from airbyte.agents import _api_util
 16from airbyte.agents import skills as _skills
 17from airbyte.agents.connectors import AgentConnector, _resolve_connector_lookup
 18from airbyte.agents.models import (
 19    AgentConnectorInfo,
 20    AgentSkillDocs,
 21    AgentWorkspaceInfo,
 22)
 23from airbyte.agents.skills import AgentSkill
 24from airbyte.cloud._credentials import _AirbyteCredentials
 25from airbyte.cloud.workspaces import CloudWorkspace
 26from airbyte.exceptions import AirbyteError, PyAirbyteInputError
 27
 28
 29if TYPE_CHECKING:
 30    from airbyte.secrets.base import SecretString
 31
 32
 33class AgentWorkspace:
 34    """A workspace on the Airbyte Agents platform.
 35
 36    Airbyte Cloud credentials authenticate against the Agents API, so this class reads the
 37    same `AIRBYTE_CLOUD_*` environment variables as `airbyte.cloud.CloudWorkspace`.
 38
 39    ```python
 40    from airbyte import agents
 41
 42    workspace = agents.AgentWorkspace.from_env()
 43    for connector in workspace.list_connectors():
 44        print(connector.name)
 45    ```
 46    """
 47
 48    def __init__(
 49        self,
 50        *,
 51        workspace_id: str | None = None,
 52        organization_id: str | None = None,
 53        name: str | None = None,
 54        client_id: str | SecretString | None = None,
 55        client_secret: str | SecretString | None = None,
 56        bearer_token: str | SecretString | None = None,
 57        public_api_root: str | None = None,
 58        config_api_root: str | None = None,
 59    ) -> None:
 60        """Initialize an `AgentWorkspace`.
 61
 62        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
 63        not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` /
 64        `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset);
 65        custom roots require `AIRBYTE_AGENTS_API_URL`.
 66        """
 67        credentials = _AirbyteCredentials.from_auth(
 68            workspace_id=workspace_id,
 69            organization_id=organization_id,
 70            client_id=client_id,
 71            client_secret=client_secret,
 72            bearer_token=bearer_token,
 73            public_api_root=public_api_root,
 74            config_api_root=config_api_root,
 75            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
 76            # fallback, since an env bearer token plus explicit client creds is rejected
 77            # as mutually exclusive auth.
 78            env_vars=not (client_id or client_secret or bearer_token),
 79        )
 80        if not credentials.workspace_id:
 81            raise PyAirbyteInputError(
 82                message="Workspace ID is required.",
 83                guidance=(
 84                    "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` "
 85                    "environment variable."
 86                ),
 87            )
 88
 89        self._credentials = credentials
 90
 91        self.workspace_id: str = credentials.workspace_id
 92        """The workspace ID."""
 93
 94        self.organization_id: str | None = credentials.organization_id
 95        """The organization ID, sent to the Agents API when it is known."""
 96
 97        self.name: str | None = name
 98        """The workspace name, when known. Use `get_info()` to fetch it from the API."""
 99
100    @classmethod
101    def from_env(
102        cls,
103        workspace_id: str | None = None,
104        *,
105        organization_id: str | None = None,
106    ) -> AgentWorkspace:
107        """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables.
108
109        The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the
110        `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with
111        `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`.
112        """
113        return cls(workspace_id=workspace_id, organization_id=organization_id)
114
115    def get_info(self) -> AgentWorkspaceInfo:
116        """Fetch this workspace from the Agents API.
117
118        A successful call is authoritative proof that the workspace is reachable through
119        the Agents API with these credentials.
120        """
121        return AgentWorkspaceInfo.model_validate(
122            _api_util.get_agent_workspace(
123                workspace_id=self.workspace_id,
124                credentials=self._credentials,
125                organization_id=self.organization_id,
126            )
127        )
128
129    def list_connectors(self) -> list[AgentConnector]:
130        """List the connectors configured in this workspace."""
131        return [
132            AgentConnector(
133                connector_id=info.id,
134                name=info.name,
135                credentials=self._credentials,
136                workspace_id=self.workspace_id,
137            )
138            for info in (
139                AgentConnectorInfo.model_validate(record)
140                for record in _api_util.list_agent_connectors(
141                    workspace_id=self.workspace_id,
142                    credentials=self._credentials,
143                    organization_id=self.organization_id,
144                )
145            )
146        ]
147
148    def list_skills(self) -> list[AgentSkill]:
149        """List all skills available to this workspace, following pagination."""
150        return [
151            AgentSkill(
152                skill_id=info.id,
153                credentials=self._credentials,
154                workspace_id=self.workspace_id,
155                info=info,
156            )
157            for info in _skills.iter_skills(
158                credentials=self._credentials,
159                workspace_id=self.workspace_id,
160            )
161        ]
162
163    def get_skill(self, skill_id: str) -> AgentSkill:
164        """Get a skill by ID, without calling the Agents API."""
165        return AgentSkill(
166            skill_id,
167            credentials=self._credentials,
168            workspace_id=self.workspace_id,
169        )
170
171    def read_skill_docs(
172        self,
173        skill_id: str,
174        *,
175        section: str | None = None,
176    ) -> AgentSkillDocs:
177        """Read a skill's docs, optionally scoped to a single section.
178
179        Omit `section` for metadata, guidance, and the outline of available sections, or
180        pass an exact section `id` from the outline to read that section. Connector usage
181        docs use the `docs_skill_id` reported by `AgentConnector.inspect()`.
182        """
183        return self.get_skill(skill_id).read_docs(section=section)
184
185    def get_connector(
186        self,
187        id_or_name: str | None = None,
188        /,
189        *,
190        id: str | None = None,  # noqa: A002  # Shadows `id` deliberately, as a short alias.
191        connector_id: str | None = None,
192        name: str | None = None,
193    ) -> AgentConnector:
194        """Get a connector in this workspace, by ID or by name.
195
196        Pass a single positional value to look the connector up by either its ID or its
197        name, or name the argument to be explicit: `id` and `connector_id` are synonyms,
198        so pass whichever reads better.
199
200        Lookup by an explicit ID does not call the Agents API. Every other form lists the
201        workspace's connectors and matches on ID first, then on an exact name, then on a
202        unique substring, so `name="GitHub"` finds a connector named
203        `GitHub - <workspace_id>`. Name matching is case-insensitive.
204        """
205        lookup = _resolve_connector_lookup(
206            id_or_name,
207            id=id,
208            connector_id=connector_id,
209            name=name,
210        )
211
212        if lookup.connector_id and not lookup.name:
213            return AgentConnector(
214                connector_id=lookup.connector_id,
215                credentials=self._credentials,
216                workspace_id=self.workspace_id,
217            )
218
219        connectors = self.list_connectors()
220        if lookup.connector_id:
221            id_matches = [
222                connector
223                for connector in connectors
224                if connector.connector_id == lookup.connector_id
225            ]
226            if id_matches:
227                return id_matches[0]
228
229        name_lower = (lookup.name or "").lower()
230        matches = [
231            connector
232            for connector in connectors
233            if connector.name and connector.name.lower() == name_lower
234        ] or [
235            connector
236            for connector in connectors
237            if connector.name and name_lower in connector.name.lower()
238        ]
239        if not matches:
240            raise AirbyteError(
241                message="No connector found with the given ID or name.",
242                guidance="Use `list_connectors()` to see the available connectors.",
243                context={"lookup": lookup.name, "workspace_id": self.workspace_id},
244            )
245        if len(matches) > 1:
246            raise AirbyteError(
247                message="Multiple connectors matched the given name.",
248                guidance="Pass `connector_id`, or a name that matches only one connector.",
249                context={
250                    "name": lookup.name,
251                    "matched_names": [connector.name for connector in matches],
252                },
253            )
254        return matches[0]
255
256    def as_cloud_workspace(self) -> CloudWorkspace:
257        """Return this workspace as an `airbyte.cloud.CloudWorkspace`.
258
259        Every Agents workspace is also a Cloud workspace, so this conversion always
260        succeeds without calling either API.
261        """
262        return CloudWorkspace(
263            workspace_id=self.workspace_id,
264            client_id=self._credentials.client_id,
265            client_secret=self._credentials.client_secret,
266            bearer_token=self._credentials.bearer_token,
267            api_root=self._credentials.public_api_root,
268            config_api_root=self._credentials.config_api_root,
269        )
270
271    @classmethod
272    def from_cloud_workspace(
273        cls,
274        cloud_workspace: CloudWorkspace,
275        *,
276        organization_id: str | None = None,
277        verify: bool = True,
278    ) -> AgentWorkspace:
279        """Return a Cloud workspace as an `AgentWorkspace`.
280
281        Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is
282        reachable through the Agents API: the organization needs an Airbyte Agents
283        subscription. By default this is verified by fetching the workspace from the Agents
284        API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to
285        skip that call.
286
287        Raises `AirbyteAgentsUnavailableError` when the Cloud workspace uses non-public Cloud API
288        roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so the
289        token exchange stays on the same deployment.
290        """
291        _api_util.check_public_cloud_api_roots(
292            cloud_workspace._credentials,  # noqa: SLF001  # Same-domain conversion.
293        )
294        workspace = cls(
295            workspace_id=cloud_workspace.workspace_id,
296            organization_id=organization_id,
297            client_id=cloud_workspace.client_id,
298            client_secret=cloud_workspace.client_secret,
299            bearer_token=cloud_workspace.bearer_token,
300            public_api_root=cloud_workspace._credentials.public_api_root,  # noqa: SLF001
301            config_api_root=cloud_workspace._credentials.config_api_root,  # noqa: SLF001
302        )
303        if verify:
304            workspace.get_info()
305        return workspace
class AgentWorkspace:
 34class AgentWorkspace:
 35    """A workspace on the Airbyte Agents platform.
 36
 37    Airbyte Cloud credentials authenticate against the Agents API, so this class reads the
 38    same `AIRBYTE_CLOUD_*` environment variables as `airbyte.cloud.CloudWorkspace`.
 39
 40    ```python
 41    from airbyte import agents
 42
 43    workspace = agents.AgentWorkspace.from_env()
 44    for connector in workspace.list_connectors():
 45        print(connector.name)
 46    ```
 47    """
 48
 49    def __init__(
 50        self,
 51        *,
 52        workspace_id: str | None = None,
 53        organization_id: str | None = None,
 54        name: str | None = None,
 55        client_id: str | SecretString | None = None,
 56        client_secret: str | SecretString | None = None,
 57        bearer_token: str | SecretString | None = None,
 58        public_api_root: str | None = None,
 59        config_api_root: str | None = None,
 60    ) -> None:
 61        """Initialize an `AgentWorkspace`.
 62
 63        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
 64        not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` /
 65        `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset);
 66        custom roots require `AIRBYTE_AGENTS_API_URL`.
 67        """
 68        credentials = _AirbyteCredentials.from_auth(
 69            workspace_id=workspace_id,
 70            organization_id=organization_id,
 71            client_id=client_id,
 72            client_secret=client_secret,
 73            bearer_token=bearer_token,
 74            public_api_root=public_api_root,
 75            config_api_root=config_api_root,
 76            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
 77            # fallback, since an env bearer token plus explicit client creds is rejected
 78            # as mutually exclusive auth.
 79            env_vars=not (client_id or client_secret or bearer_token),
 80        )
 81        if not credentials.workspace_id:
 82            raise PyAirbyteInputError(
 83                message="Workspace ID is required.",
 84                guidance=(
 85                    "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` "
 86                    "environment variable."
 87                ),
 88            )
 89
 90        self._credentials = credentials
 91
 92        self.workspace_id: str = credentials.workspace_id
 93        """The workspace ID."""
 94
 95        self.organization_id: str | None = credentials.organization_id
 96        """The organization ID, sent to the Agents API when it is known."""
 97
 98        self.name: str | None = name
 99        """The workspace name, when known. Use `get_info()` to fetch it from the API."""
100
101    @classmethod
102    def from_env(
103        cls,
104        workspace_id: str | None = None,
105        *,
106        organization_id: str | None = None,
107    ) -> AgentWorkspace:
108        """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables.
109
110        The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the
111        `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with
112        `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`.
113        """
114        return cls(workspace_id=workspace_id, organization_id=organization_id)
115
116    def get_info(self) -> AgentWorkspaceInfo:
117        """Fetch this workspace from the Agents API.
118
119        A successful call is authoritative proof that the workspace is reachable through
120        the Agents API with these credentials.
121        """
122        return AgentWorkspaceInfo.model_validate(
123            _api_util.get_agent_workspace(
124                workspace_id=self.workspace_id,
125                credentials=self._credentials,
126                organization_id=self.organization_id,
127            )
128        )
129
130    def list_connectors(self) -> list[AgentConnector]:
131        """List the connectors configured in this workspace."""
132        return [
133            AgentConnector(
134                connector_id=info.id,
135                name=info.name,
136                credentials=self._credentials,
137                workspace_id=self.workspace_id,
138            )
139            for info in (
140                AgentConnectorInfo.model_validate(record)
141                for record in _api_util.list_agent_connectors(
142                    workspace_id=self.workspace_id,
143                    credentials=self._credentials,
144                    organization_id=self.organization_id,
145                )
146            )
147        ]
148
149    def list_skills(self) -> list[AgentSkill]:
150        """List all skills available to this workspace, following pagination."""
151        return [
152            AgentSkill(
153                skill_id=info.id,
154                credentials=self._credentials,
155                workspace_id=self.workspace_id,
156                info=info,
157            )
158            for info in _skills.iter_skills(
159                credentials=self._credentials,
160                workspace_id=self.workspace_id,
161            )
162        ]
163
164    def get_skill(self, skill_id: str) -> AgentSkill:
165        """Get a skill by ID, without calling the Agents API."""
166        return AgentSkill(
167            skill_id,
168            credentials=self._credentials,
169            workspace_id=self.workspace_id,
170        )
171
172    def read_skill_docs(
173        self,
174        skill_id: str,
175        *,
176        section: str | None = None,
177    ) -> AgentSkillDocs:
178        """Read a skill's docs, optionally scoped to a single section.
179
180        Omit `section` for metadata, guidance, and the outline of available sections, or
181        pass an exact section `id` from the outline to read that section. Connector usage
182        docs use the `docs_skill_id` reported by `AgentConnector.inspect()`.
183        """
184        return self.get_skill(skill_id).read_docs(section=section)
185
186    def get_connector(
187        self,
188        id_or_name: str | None = None,
189        /,
190        *,
191        id: str | None = None,  # noqa: A002  # Shadows `id` deliberately, as a short alias.
192        connector_id: str | None = None,
193        name: str | None = None,
194    ) -> AgentConnector:
195        """Get a connector in this workspace, by ID or by name.
196
197        Pass a single positional value to look the connector up by either its ID or its
198        name, or name the argument to be explicit: `id` and `connector_id` are synonyms,
199        so pass whichever reads better.
200
201        Lookup by an explicit ID does not call the Agents API. Every other form lists the
202        workspace's connectors and matches on ID first, then on an exact name, then on a
203        unique substring, so `name="GitHub"` finds a connector named
204        `GitHub - <workspace_id>`. Name matching is case-insensitive.
205        """
206        lookup = _resolve_connector_lookup(
207            id_or_name,
208            id=id,
209            connector_id=connector_id,
210            name=name,
211        )
212
213        if lookup.connector_id and not lookup.name:
214            return AgentConnector(
215                connector_id=lookup.connector_id,
216                credentials=self._credentials,
217                workspace_id=self.workspace_id,
218            )
219
220        connectors = self.list_connectors()
221        if lookup.connector_id:
222            id_matches = [
223                connector
224                for connector in connectors
225                if connector.connector_id == lookup.connector_id
226            ]
227            if id_matches:
228                return id_matches[0]
229
230        name_lower = (lookup.name or "").lower()
231        matches = [
232            connector
233            for connector in connectors
234            if connector.name and connector.name.lower() == name_lower
235        ] or [
236            connector
237            for connector in connectors
238            if connector.name and name_lower in connector.name.lower()
239        ]
240        if not matches:
241            raise AirbyteError(
242                message="No connector found with the given ID or name.",
243                guidance="Use `list_connectors()` to see the available connectors.",
244                context={"lookup": lookup.name, "workspace_id": self.workspace_id},
245            )
246        if len(matches) > 1:
247            raise AirbyteError(
248                message="Multiple connectors matched the given name.",
249                guidance="Pass `connector_id`, or a name that matches only one connector.",
250                context={
251                    "name": lookup.name,
252                    "matched_names": [connector.name for connector in matches],
253                },
254            )
255        return matches[0]
256
257    def as_cloud_workspace(self) -> CloudWorkspace:
258        """Return this workspace as an `airbyte.cloud.CloudWorkspace`.
259
260        Every Agents workspace is also a Cloud workspace, so this conversion always
261        succeeds without calling either API.
262        """
263        return CloudWorkspace(
264            workspace_id=self.workspace_id,
265            client_id=self._credentials.client_id,
266            client_secret=self._credentials.client_secret,
267            bearer_token=self._credentials.bearer_token,
268            api_root=self._credentials.public_api_root,
269            config_api_root=self._credentials.config_api_root,
270        )
271
272    @classmethod
273    def from_cloud_workspace(
274        cls,
275        cloud_workspace: CloudWorkspace,
276        *,
277        organization_id: str | None = None,
278        verify: bool = True,
279    ) -> AgentWorkspace:
280        """Return a Cloud workspace as an `AgentWorkspace`.
281
282        Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is
283        reachable through the Agents API: the organization needs an Airbyte Agents
284        subscription. By default this is verified by fetching the workspace from the Agents
285        API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to
286        skip that call.
287
288        Raises `AirbyteAgentsUnavailableError` when the Cloud workspace uses non-public Cloud API
289        roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so the
290        token exchange stays on the same deployment.
291        """
292        _api_util.check_public_cloud_api_roots(
293            cloud_workspace._credentials,  # noqa: SLF001  # Same-domain conversion.
294        )
295        workspace = cls(
296            workspace_id=cloud_workspace.workspace_id,
297            organization_id=organization_id,
298            client_id=cloud_workspace.client_id,
299            client_secret=cloud_workspace.client_secret,
300            bearer_token=cloud_workspace.bearer_token,
301            public_api_root=cloud_workspace._credentials.public_api_root,  # noqa: SLF001
302            config_api_root=cloud_workspace._credentials.config_api_root,  # noqa: SLF001
303        )
304        if verify:
305            workspace.get_info()
306        return workspace

A workspace on the Airbyte Agents platform.

Airbyte Cloud credentials authenticate against the Agents API, so this class reads the same AIRBYTE_CLOUD_* environment variables as airbyte.cloud.CloudWorkspace.

from airbyte import agents

workspace = agents.AgentWorkspace.from_env()
for connector in workspace.list_connectors():
    print(connector.name)
AgentWorkspace( *, workspace_id: str | None = None, organization_id: str | None = None, name: str | None = None, client_id: str | airbyte.secrets.SecretString | None = None, client_secret: str | airbyte.secrets.SecretString | None = None, bearer_token: str | airbyte.secrets.SecretString | None = None, public_api_root: str | None = None, config_api_root: str | None = None)
49    def __init__(
50        self,
51        *,
52        workspace_id: str | None = None,
53        organization_id: str | None = None,
54        name: str | None = None,
55        client_id: str | SecretString | None = None,
56        client_secret: str | SecretString | None = None,
57        bearer_token: str | SecretString | None = None,
58        public_api_root: str | None = None,
59        config_api_root: str | None = None,
60    ) -> None:
61        """Initialize an `AgentWorkspace`.
62
63        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
64        not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` /
65        `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset);
66        custom roots require `AIRBYTE_AGENTS_API_URL`.
67        """
68        credentials = _AirbyteCredentials.from_auth(
69            workspace_id=workspace_id,
70            organization_id=organization_id,
71            client_id=client_id,
72            client_secret=client_secret,
73            bearer_token=bearer_token,
74            public_api_root=public_api_root,
75            config_api_root=config_api_root,
76            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
77            # fallback, since an env bearer token plus explicit client creds is rejected
78            # as mutually exclusive auth.
79            env_vars=not (client_id or client_secret or bearer_token),
80        )
81        if not credentials.workspace_id:
82            raise PyAirbyteInputError(
83                message="Workspace ID is required.",
84                guidance=(
85                    "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` "
86                    "environment variable."
87                ),
88            )
89
90        self._credentials = credentials
91
92        self.workspace_id: str = credentials.workspace_id
93        """The workspace ID."""
94
95        self.organization_id: str | None = credentials.organization_id
96        """The organization ID, sent to the Agents API when it is known."""
97
98        self.name: str | None = name
99        """The workspace name, when known. Use `get_info()` to fetch it from the API."""

Initialize an AgentWorkspace.

Credentials fall back to the AIRBYTE_CLOUD_* environment variables when they are not passed explicitly. API roots default to the AIRBYTE_CLOUD_API_URL / AIRBYTE_CLOUD_CONFIG_API_URL environment variables (public Airbyte Cloud when unset); custom roots require AIRBYTE_AGENTS_API_URL.

workspace_id: str

The workspace ID.

organization_id: str | None

The organization ID, sent to the Agents API when it is known.

name: str | None

The workspace name, when known. Use get_info() to fetch it from the API.

@classmethod
def from_env( cls, workspace_id: str | None = None, *, organization_id: str | None = None) -> AgentWorkspace:
101    @classmethod
102    def from_env(
103        cls,
104        workspace_id: str | None = None,
105        *,
106        organization_id: str | None = None,
107    ) -> AgentWorkspace:
108        """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables.
109
110        The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the
111        `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with
112        `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`.
113        """
114        return cls(workspace_id=workspace_id, organization_id=organization_id)

Create an AgentWorkspace from the AIRBYTE_CLOUD_* environment variables.

The variables used are AIRBYTE_CLOUD_BEARER_TOKEN or the AIRBYTE_CLOUD_CLIENT_ID and AIRBYTE_CLOUD_CLIENT_SECRET pair, along with AIRBYTE_CLOUD_WORKSPACE_ID and AIRBYTE_CLOUD_ORGANIZATION_ID.

def get_info(self) -> airbyte.agents.AgentWorkspaceInfo:
116    def get_info(self) -> AgentWorkspaceInfo:
117        """Fetch this workspace from the Agents API.
118
119        A successful call is authoritative proof that the workspace is reachable through
120        the Agents API with these credentials.
121        """
122        return AgentWorkspaceInfo.model_validate(
123            _api_util.get_agent_workspace(
124                workspace_id=self.workspace_id,
125                credentials=self._credentials,
126                organization_id=self.organization_id,
127            )
128        )

Fetch this workspace from the Agents API.

A successful call is authoritative proof that the workspace is reachable through the Agents API with these credentials.

def list_connectors(self) -> list[airbyte.agents.AgentConnector]:
130    def list_connectors(self) -> list[AgentConnector]:
131        """List the connectors configured in this workspace."""
132        return [
133            AgentConnector(
134                connector_id=info.id,
135                name=info.name,
136                credentials=self._credentials,
137                workspace_id=self.workspace_id,
138            )
139            for info in (
140                AgentConnectorInfo.model_validate(record)
141                for record in _api_util.list_agent_connectors(
142                    workspace_id=self.workspace_id,
143                    credentials=self._credentials,
144                    organization_id=self.organization_id,
145                )
146            )
147        ]

List the connectors configured in this workspace.

def list_skills(self) -> list[airbyte.agents.AgentSkill]:
149    def list_skills(self) -> list[AgentSkill]:
150        """List all skills available to this workspace, following pagination."""
151        return [
152            AgentSkill(
153                skill_id=info.id,
154                credentials=self._credentials,
155                workspace_id=self.workspace_id,
156                info=info,
157            )
158            for info in _skills.iter_skills(
159                credentials=self._credentials,
160                workspace_id=self.workspace_id,
161            )
162        ]

List all skills available to this workspace, following pagination.

def get_skill(self, skill_id: str) -> airbyte.agents.AgentSkill:
164    def get_skill(self, skill_id: str) -> AgentSkill:
165        """Get a skill by ID, without calling the Agents API."""
166        return AgentSkill(
167            skill_id,
168            credentials=self._credentials,
169            workspace_id=self.workspace_id,
170        )

Get a skill by ID, without calling the Agents API.

def read_skill_docs( self, skill_id: str, *, section: str | None = None) -> airbyte.agents.AgentSkillDocs:
172    def read_skill_docs(
173        self,
174        skill_id: str,
175        *,
176        section: str | None = None,
177    ) -> AgentSkillDocs:
178        """Read a skill's docs, optionally scoped to a single section.
179
180        Omit `section` for metadata, guidance, and the outline of available sections, or
181        pass an exact section `id` from the outline to read that section. Connector usage
182        docs use the `docs_skill_id` reported by `AgentConnector.inspect()`.
183        """
184        return self.get_skill(skill_id).read_docs(section=section)

Read a skill's docs, optionally scoped to a single section.

Omit section for metadata, guidance, and the outline of available sections, or pass an exact section id from the outline to read that section. Connector usage docs use the docs_skill_id reported by AgentConnector.inspect().

def get_connector( self, id_or_name: str | None = None, /, *, id: str | None = None, connector_id: str | None = None, name: str | None = None) -> airbyte.agents.AgentConnector:
186    def get_connector(
187        self,
188        id_or_name: str | None = None,
189        /,
190        *,
191        id: str | None = None,  # noqa: A002  # Shadows `id` deliberately, as a short alias.
192        connector_id: str | None = None,
193        name: str | None = None,
194    ) -> AgentConnector:
195        """Get a connector in this workspace, by ID or by name.
196
197        Pass a single positional value to look the connector up by either its ID or its
198        name, or name the argument to be explicit: `id` and `connector_id` are synonyms,
199        so pass whichever reads better.
200
201        Lookup by an explicit ID does not call the Agents API. Every other form lists the
202        workspace's connectors and matches on ID first, then on an exact name, then on a
203        unique substring, so `name="GitHub"` finds a connector named
204        `GitHub - <workspace_id>`. Name matching is case-insensitive.
205        """
206        lookup = _resolve_connector_lookup(
207            id_or_name,
208            id=id,
209            connector_id=connector_id,
210            name=name,
211        )
212
213        if lookup.connector_id and not lookup.name:
214            return AgentConnector(
215                connector_id=lookup.connector_id,
216                credentials=self._credentials,
217                workspace_id=self.workspace_id,
218            )
219
220        connectors = self.list_connectors()
221        if lookup.connector_id:
222            id_matches = [
223                connector
224                for connector in connectors
225                if connector.connector_id == lookup.connector_id
226            ]
227            if id_matches:
228                return id_matches[0]
229
230        name_lower = (lookup.name or "").lower()
231        matches = [
232            connector
233            for connector in connectors
234            if connector.name and connector.name.lower() == name_lower
235        ] or [
236            connector
237            for connector in connectors
238            if connector.name and name_lower in connector.name.lower()
239        ]
240        if not matches:
241            raise AirbyteError(
242                message="No connector found with the given ID or name.",
243                guidance="Use `list_connectors()` to see the available connectors.",
244                context={"lookup": lookup.name, "workspace_id": self.workspace_id},
245            )
246        if len(matches) > 1:
247            raise AirbyteError(
248                message="Multiple connectors matched the given name.",
249                guidance="Pass `connector_id`, or a name that matches only one connector.",
250                context={
251                    "name": lookup.name,
252                    "matched_names": [connector.name for connector in matches],
253                },
254            )
255        return matches[0]

Get a connector in this workspace, by ID or by name.

Pass a single positional value to look the connector up by either its ID or its name, or name the argument to be explicit: id and connector_id are synonyms, so pass whichever reads better.

Lookup by an explicit ID does not call the Agents API. Every other form lists the workspace's connectors and matches on ID first, then on an exact name, then on a unique substring, so name="GitHub" finds a connector named GitHub - <workspace_id>. Name matching is case-insensitive.

def as_cloud_workspace(self) -> airbyte.cloud.CloudWorkspace:
257    def as_cloud_workspace(self) -> CloudWorkspace:
258        """Return this workspace as an `airbyte.cloud.CloudWorkspace`.
259
260        Every Agents workspace is also a Cloud workspace, so this conversion always
261        succeeds without calling either API.
262        """
263        return CloudWorkspace(
264            workspace_id=self.workspace_id,
265            client_id=self._credentials.client_id,
266            client_secret=self._credentials.client_secret,
267            bearer_token=self._credentials.bearer_token,
268            api_root=self._credentials.public_api_root,
269            config_api_root=self._credentials.config_api_root,
270        )

Return this workspace as an airbyte.cloud.CloudWorkspace.

Every Agents workspace is also a Cloud workspace, so this conversion always succeeds without calling either API.

@classmethod
def from_cloud_workspace( cls, cloud_workspace: airbyte.cloud.CloudWorkspace, *, organization_id: str | None = None, verify: bool = True) -> AgentWorkspace:
272    @classmethod
273    def from_cloud_workspace(
274        cls,
275        cloud_workspace: CloudWorkspace,
276        *,
277        organization_id: str | None = None,
278        verify: bool = True,
279    ) -> AgentWorkspace:
280        """Return a Cloud workspace as an `AgentWorkspace`.
281
282        Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is
283        reachable through the Agents API: the organization needs an Airbyte Agents
284        subscription. By default this is verified by fetching the workspace from the Agents
285        API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to
286        skip that call.
287
288        Raises `AirbyteAgentsUnavailableError` when the Cloud workspace uses non-public Cloud API
289        roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so the
290        token exchange stays on the same deployment.
291        """
292        _api_util.check_public_cloud_api_roots(
293            cloud_workspace._credentials,  # noqa: SLF001  # Same-domain conversion.
294        )
295        workspace = cls(
296            workspace_id=cloud_workspace.workspace_id,
297            organization_id=organization_id,
298            client_id=cloud_workspace.client_id,
299            client_secret=cloud_workspace.client_secret,
300            bearer_token=cloud_workspace.bearer_token,
301            public_api_root=cloud_workspace._credentials.public_api_root,  # noqa: SLF001
302            config_api_root=cloud_workspace._credentials.config_api_root,  # noqa: SLF001
303        )
304        if verify:
305            workspace.get_info()
306        return workspace

Return a Cloud workspace as an AgentWorkspace.

Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is reachable through the Agents API: the organization needs an Airbyte Agents subscription. By default this is verified by fetching the workspace from the Agents API, which raises AirbyteError when it is not eligible. Pass verify=False to skip that call.

Raises AirbyteAgentsUnavailableError when the Cloud workspace uses non-public Cloud API roots unless AIRBYTE_AGENTS_API_URL is set; the Cloud API roots are carried over so the token exchange stays on the same deployment.