airbyte.agents

PyAirbyte classes and methods for the Airbyte Agents platform.

WARNING: The Airbyte Agents interfaces in this module are experimental and may change without notice between minor versions of PyAirbyte, including breaking changes to class names, method signatures, and result models. Pin an exact PyAirbyte version if you depend on them.

Airbyte Agents connectors expose read and write actions on individual entities, executed one action at a time, rather than the batch record replication that airbyte.cloud provides. This module is that interface.

Airbyte Cloud credentials authenticate against the Agents API, so no Agents-specific credentials or environment variables exist: the AIRBYTE_CLOUD_* variables are reused.

Usage Examples

Read entities from a connector, paging automatically as you iterate:

from airbyte import agents

workspace = agents.AgentWorkspace.from_env()
connector = workspace.get_connector("GitHub")  # by ID or name (case insensitive)

for issue in connector.iter_entities(
    "issues",
    api_args={"repository": "airbytehq/PyAirbyte"},  # Passthrough API args
):
    print(issue["title"])

Fetch a single page instead, when the result's status and metadata are needed:

result = connector.list_entities(
    "issues",
    api_args={"repository": "airbytehq/PyAirbyte"},
    page_size=50,
)
print(result.status, result.has_next_page)
for entity in result.entities:
    print(entity["title"])

Pass result.end_cursor back as cursor to page through manually:

cursor = None
while True:
    result = connector.list_entities(
        "issues",
        api_args={"repository": "airbytehq/PyAirbyte"},
        cursor=cursor,
    )
    print(len(result.entities))
    if not result.has_next_page:
        break
    cursor = result.end_cursor

Discover what a connector supports, and what an organization can reach:

organization = agents.AgentOrganization.from_env()
for workspace in organization.list_workspaces():
    print(workspace.workspace_id, workspace.name)

print(connector.describe().source_definition_name)

Convert between the Cloud and Agents domains:

from airbyte.cloud import CloudWorkspace

cloud_workspace = CloudWorkspace.from_env()
agent_workspace = agents.AgentWorkspace.from_cloud_workspace(cloud_workspace)
back_to_cloud = agent_workspace.as_cloud_workspace()
  1# Copyright (c) 2026 Airbyte, Inc., all rights reserved.
  2"""PyAirbyte classes and methods for the Airbyte Agents platform.
  3
  4> **WARNING:**
  5> The Airbyte Agents interfaces in this module are experimental and may change without notice
  6> between minor versions of PyAirbyte, including breaking changes to class names, method
  7> signatures, and result models. Pin an exact PyAirbyte version if you depend on them.
  8
  9Airbyte Agents connectors expose read and write actions on individual entities, executed
 10one action at a time, rather than the batch record replication that `airbyte.cloud`
 11provides. This module is that interface.
 12
 13Airbyte Cloud credentials authenticate against the Agents API, so no Agents-specific
 14credentials or environment variables exist: the `AIRBYTE_CLOUD_*` variables are reused.
 15
 16## Usage Examples
 17
 18Read entities from a connector, paging automatically as you iterate:
 19
 20```python
 21from airbyte import agents
 22
 23workspace = agents.AgentWorkspace.from_env()
 24connector = workspace.get_connector("GitHub")  # by ID or name (case insensitive)
 25
 26for issue in connector.iter_entities(
 27    "issues",
 28    api_args={"repository": "airbytehq/PyAirbyte"},  # Passthrough API args
 29):
 30    print(issue["title"])
 31```
 32
 33Fetch a single page instead, when the result's status and metadata are needed:
 34
 35```python
 36result = connector.list_entities(
 37    "issues",
 38    api_args={"repository": "airbytehq/PyAirbyte"},
 39    page_size=50,
 40)
 41print(result.status, result.has_next_page)
 42for entity in result.entities:
 43    print(entity["title"])
 44```
 45
 46Pass `result.end_cursor` back as `cursor` to page through manually:
 47
 48```python
 49cursor = None
 50while True:
 51    result = connector.list_entities(
 52        "issues",
 53        api_args={"repository": "airbytehq/PyAirbyte"},
 54        cursor=cursor,
 55    )
 56    print(len(result.entities))
 57    if not result.has_next_page:
 58        break
 59    cursor = result.end_cursor
 60```
 61
 62Discover what a connector supports, and what an organization can reach:
 63
 64```python
 65organization = agents.AgentOrganization.from_env()
 66for workspace in organization.list_workspaces():
 67    print(workspace.workspace_id, workspace.name)
 68
 69print(connector.describe().source_definition_name)
 70```
 71
 72Convert between the Cloud and Agents domains:
 73
 74```python
 75from airbyte.cloud import CloudWorkspace
 76
 77cloud_workspace = CloudWorkspace.from_env()
 78agent_workspace = agents.AgentWorkspace.from_cloud_workspace(cloud_workspace)
 79back_to_cloud = agent_workspace.as_cloud_workspace()
 80```
 81"""
 82
 83from __future__ import annotations
 84
 85from typing import TYPE_CHECKING
 86
 87from airbyte.agents.connectors import AgentConnector
 88from airbyte.agents.models import (
 89    AgentConnectorDetails,
 90    AgentConnectorInfo,
 91    AgentConnectorMetadata,
 92    AgentContextStoreEntity,
 93    AgentContextStoreReadiness,
 94    AgentExecuteResult,
 95    AgentExecutionMetadata,
 96    AgentWorkspaceInfo,
 97)
 98from airbyte.agents.organizations import AgentOrganization
 99from airbyte.agents.workspaces import AgentWorkspace
100
101
102# Submodules imported here for documentation reasons: https://github.com/mitmproxy/pdoc/issues/757
103if TYPE_CHECKING:
104    # ruff: noqa: TC004
105    from airbyte.agents import (
106        connectors,
107        models,
108        organizations,
109        workspaces,
110    )
111
112
113__all__ = [
114    # Submodules
115    "connectors",
116    "models",
117    "organizations",
118    "workspaces",
119    # Classes
120    "AgentConnector",
121    "AgentConnectorDetails",
122    "AgentConnectorInfo",
123    "AgentConnectorMetadata",
124    "AgentContextStoreEntity",
125    "AgentContextStoreReadiness",
126    "AgentExecuteResult",
127    "AgentExecutionMetadata",
128    "AgentOrganization",
129    "AgentWorkspace",
130    "AgentWorkspaceInfo",
131]
class AgentConnector:
113class AgentConnector:
114    """A connector in an Airbyte Agents workspace.
115
116    Get one from `AgentWorkspace.get_connector()` rather than constructing it directly.
117
118    ```python
119    from airbyte import agents
120
121    workspace = agents.AgentWorkspace.from_env()
122    connector = workspace.get_connector("GitHub")  # by ID or name (case insensitive)
123    result = connector.list_entities("issues", api_args={"repository": "airbytehq/PyAirbyte"})
124    for entity in result.entities:
125        print(entity["title"])
126    ```
127    """
128
129    def __init__(
130        self,
131        connector_id: str,
132        *,
133        credentials: _AirbyteCredentials,
134        name: str | None = None,
135    ) -> None:
136        """Initialize an `AgentConnector`. Prefer `AgentWorkspace.get_connector()`."""
137        self.connector_id = connector_id
138        """The connector ID."""
139
140        self._credentials = credentials
141        self._name = name
142        self._details: AgentConnectorDetails | None = None
143
144    @property
145    def name(self) -> str | None:
146        """The connector name, fetched from the Agents API if not already known."""
147        if self._name is None:
148            self._name = self.describe().name
149        return self._name
150
151    def describe(self, *, force_refresh: bool = False) -> AgentConnectorDetails:
152        """Return connector metadata from the Agents API `inspect` endpoint.
153
154        The result is cached; pass `force_refresh=True` to fetch it again.
155        """
156        if self._details is None or force_refresh:
157            self._details = AgentConnectorDetails.model_validate(
158                _api_util.inspect_agent_connector(
159                    connector_id=self.connector_id,
160                    credentials=self._credentials,
161                    organization_id=self._credentials.organization_id,
162                )
163            )
164            self._name = self._details.name or self._name
165        return self._details
166
167    def execute(  # noqa: PLR0913  # Explicit args are the point of this public API.
168        self,
169        entity_type: str,
170        action: str,
171        api_args: dict[str, Any] | None = None,
172        *,
173        select_fields: list[str] | None = None,
174        exclude_fields: list[str] | None = None,
175        page_size: int | None = None,
176        cursor: str | None = None,
177        skip_truncation: bool = True,
178        intent: str | None = None,
179    ) -> AgentExecuteResult:
180        """Execute a single action against one entity type on this connector.
181
182        `entity_type` and `action` are connector-specific, for example `issues` and `list`.
183        Use `describe()` to see what a connector supports.
184
185        `api_args` holds connector-specific arguments passed through to the connector, for
186        example `{"repository": "airbytehq/PyAirbyte"}`. All other arguments are interpreted
187        by PyAirbyte or by the Agents API itself:
188
189        - `select_fields` and `exclude_fields` prune fields from returned entities.
190        - `page_size` and `cursor` are merged into `api_args` as pagination arguments, where
191          the connector receives `page_size` as its own `limit`. Pass the `end_cursor` of a
192          previous result as `cursor` to fetch the next page.
193        - `skip_truncation` disables the Agents API's default truncation of large payloads.
194        - `intent` is a free-text description of why the action is being run, which some
195          connectors use to refine results.
196
197        The `download` action is rejected, because it returns a binary stream and PyAirbyte
198        does not yet support streaming responses.
199        """
200        if action in UNSUPPORTED_ACTIONS:
201            raise PyAirbyteInputError(
202                message=f"The {action!r} action is not supported by PyAirbyte.",
203                guidance=(
204                    "This action returns a binary stream instead of JSON, and PyAirbyte does "
205                    "not yet support streaming responses."
206                ),
207                context={"entity_type": entity_type, "action": action},
208            )
209
210        request_body: dict[str, Any] = {
211            "entity": entity_type,
212            "action": action,
213            "params": _build_params(api_args=api_args, page_size=page_size, cursor=cursor),
214            "skip_truncation": skip_truncation,
215        }
216        if select_fields is not None:
217            request_body["select_fields"] = select_fields
218        if exclude_fields is not None:
219            request_body["exclude_fields"] = exclude_fields
220        if intent is not None:
221            request_body["intent"] = intent
222
223        return AgentExecuteResult.model_validate(
224            _api_util.execute_agent_connector_action(
225                connector_id=self.connector_id,
226                request_body=request_body,
227                credentials=self._credentials,
228                organization_id=self._credentials.organization_id,
229            )
230        )
231
232    def list_entities(
233        self,
234        entity_type: str,
235        api_args: dict[str, Any] | None = None,
236        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
237    ) -> AgentExecuteResult:
238        """Run the `list` action, which returns a page of entities of `entity_type`."""
239        return self.execute(entity_type, "list", api_args, **kwargs)
240
241    def iter_entities(
242        self,
243        entity_type: str,
244        api_args: dict[str, Any] | None = None,
245        *,
246        limit: int | None = None,
247        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `list_entities()`.
248    ) -> Iterator[dict[str, Any]]:
249        """Yield entities of `entity_type`, following the connector's pagination cursor.
250
251        This is the pagination-free way to read entities: each page is fetched lazily as
252        the caller iterates, so no cursor bookkeeping is needed.
253
254        ```python
255        for issue in connector.iter_entities("issues", {"repository": "airbytehq/PyAirbyte"}):
256            print(issue["title"])
257        ```
258
259        `limit` caps how many entities are yielded in total, which matters for entity types
260        with no natural end. Pass `page_size` to control how many are fetched per request.
261
262        Iteration stops early if the connector reports another page without advancing its
263        cursor, rather than requesting the same page forever.
264
265        Use `list_entities()` instead when a single page is enough, or when the result's
266        `status`, `warning`, or `execution_metadata` are needed.
267        """
268        cursor: str | None = kwargs.pop("cursor", None)
269        seen_cursors: set[str] = set()
270        yielded = 0
271
272        while True:
273            result = self.list_entities(entity_type, api_args, cursor=cursor, **kwargs)
274            for agent_entity in result.entities:
275                yield agent_entity
276                yielded += 1
277                if limit is not None and yielded >= limit:
278                    return
279
280            cursor = result.end_cursor
281            if not result.has_next_page or cursor is None or cursor in seen_cursors:
282                return
283            seen_cursors.add(cursor)
284
285    def search_entities(
286        self,
287        entity_type: str,
288        api_args: dict[str, Any] | None = None,
289        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
290    ) -> AgentExecuteResult:
291        """Run the `search` action, which returns matching entities of `entity_type`."""
292        return self.execute(entity_type, "search", api_args, **kwargs)
293
294    def get_entity(
295        self,
296        entity_type: str,
297        api_args: dict[str, Any] | None = None,
298        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
299    ) -> AgentExecuteResult:
300        """Run the `get` action, which returns a single entity of `entity_type`."""
301        return self.execute(entity_type, "get", api_args, **kwargs)
302
303    def create_entity(
304        self,
305        entity_type: str,
306        api_args: dict[str, Any] | None = None,
307        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
308    ) -> AgentExecuteResult:
309        """Run the `create` action, which creates an entity of `entity_type`."""
310        return self.execute(entity_type, "create", api_args, **kwargs)
311
312    def update_entity(
313        self,
314        entity_type: str,
315        api_args: dict[str, Any] | None = None,
316        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
317    ) -> AgentExecuteResult:
318        """Run the `update` action, which updates an entity of `entity_type`."""
319        return self.execute(entity_type, "update", api_args, **kwargs)
320
321    def delete_entity(
322        self,
323        entity_type: str,
324        api_args: dict[str, Any] | None = None,
325        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
326    ) -> AgentExecuteResult:
327        """Run the `delete` action, which deletes an entity of `entity_type`."""
328        return self.execute(entity_type, "delete", api_args, **kwargs)

A connector in an Airbyte Agents workspace.

Get one from AgentWorkspace.get_connector() rather than constructing it directly.

from airbyte import agents

workspace = agents.AgentWorkspace.from_env()
connector = workspace.get_connector("GitHub")  # by ID or name (case insensitive)
result = connector.list_entities("issues", api_args={"repository": "airbytehq/PyAirbyte"})
for entity in result.entities:
    print(entity["title"])
AgentConnector( connector_id: str, *, credentials: airbyte.cloud._credentials._AirbyteCredentials, name: str | None = None)
129    def __init__(
130        self,
131        connector_id: str,
132        *,
133        credentials: _AirbyteCredentials,
134        name: str | None = None,
135    ) -> None:
136        """Initialize an `AgentConnector`. Prefer `AgentWorkspace.get_connector()`."""
137        self.connector_id = connector_id
138        """The connector ID."""
139
140        self._credentials = credentials
141        self._name = name
142        self._details: AgentConnectorDetails | None = None
connector_id

The connector ID.

name: str | None
144    @property
145    def name(self) -> str | None:
146        """The connector name, fetched from the Agents API if not already known."""
147        if self._name is None:
148            self._name = self.describe().name
149        return self._name

The connector name, fetched from the Agents API if not already known.

def describe( self, *, force_refresh: bool = False) -> AgentConnectorDetails:
151    def describe(self, *, force_refresh: bool = False) -> AgentConnectorDetails:
152        """Return connector metadata from the Agents API `inspect` endpoint.
153
154        The result is cached; pass `force_refresh=True` to fetch it again.
155        """
156        if self._details is None or force_refresh:
157            self._details = AgentConnectorDetails.model_validate(
158                _api_util.inspect_agent_connector(
159                    connector_id=self.connector_id,
160                    credentials=self._credentials,
161                    organization_id=self._credentials.organization_id,
162                )
163            )
164            self._name = self._details.name or self._name
165        return self._details

Return connector metadata from the Agents API inspect endpoint.

The result is cached; pass force_refresh=True to fetch it again.

def execute( self, entity_type: str, action: str, api_args: dict[str, typing.Any] | None = None, *, select_fields: list[str] | None = None, exclude_fields: list[str] | None = None, page_size: int | None = None, cursor: str | None = None, skip_truncation: bool = True, intent: str | None = None) -> AgentExecuteResult:
167    def execute(  # noqa: PLR0913  # Explicit args are the point of this public API.
168        self,
169        entity_type: str,
170        action: str,
171        api_args: dict[str, Any] | None = None,
172        *,
173        select_fields: list[str] | None = None,
174        exclude_fields: list[str] | None = None,
175        page_size: int | None = None,
176        cursor: str | None = None,
177        skip_truncation: bool = True,
178        intent: str | None = None,
179    ) -> AgentExecuteResult:
180        """Execute a single action against one entity type on this connector.
181
182        `entity_type` and `action` are connector-specific, for example `issues` and `list`.
183        Use `describe()` to see what a connector supports.
184
185        `api_args` holds connector-specific arguments passed through to the connector, for
186        example `{"repository": "airbytehq/PyAirbyte"}`. All other arguments are interpreted
187        by PyAirbyte or by the Agents API itself:
188
189        - `select_fields` and `exclude_fields` prune fields from returned entities.
190        - `page_size` and `cursor` are merged into `api_args` as pagination arguments, where
191          the connector receives `page_size` as its own `limit`. Pass the `end_cursor` of a
192          previous result as `cursor` to fetch the next page.
193        - `skip_truncation` disables the Agents API's default truncation of large payloads.
194        - `intent` is a free-text description of why the action is being run, which some
195          connectors use to refine results.
196
197        The `download` action is rejected, because it returns a binary stream and PyAirbyte
198        does not yet support streaming responses.
199        """
200        if action in UNSUPPORTED_ACTIONS:
201            raise PyAirbyteInputError(
202                message=f"The {action!r} action is not supported by PyAirbyte.",
203                guidance=(
204                    "This action returns a binary stream instead of JSON, and PyAirbyte does "
205                    "not yet support streaming responses."
206                ),
207                context={"entity_type": entity_type, "action": action},
208            )
209
210        request_body: dict[str, Any] = {
211            "entity": entity_type,
212            "action": action,
213            "params": _build_params(api_args=api_args, page_size=page_size, cursor=cursor),
214            "skip_truncation": skip_truncation,
215        }
216        if select_fields is not None:
217            request_body["select_fields"] = select_fields
218        if exclude_fields is not None:
219            request_body["exclude_fields"] = exclude_fields
220        if intent is not None:
221            request_body["intent"] = intent
222
223        return AgentExecuteResult.model_validate(
224            _api_util.execute_agent_connector_action(
225                connector_id=self.connector_id,
226                request_body=request_body,
227                credentials=self._credentials,
228                organization_id=self._credentials.organization_id,
229            )
230        )

Execute a single action against one entity type on this connector.

entity_type and action are connector-specific, for example issues and list. Use describe() to see what a connector supports.

api_args holds connector-specific arguments passed through to the connector, for example {"repository": "airbytehq/PyAirbyte"}. All other arguments are interpreted by PyAirbyte or by the Agents API itself:

  • select_fields and exclude_fields prune fields from returned entities.
  • page_size and cursor are merged into api_args as pagination arguments, where the connector receives page_size as its own limit. Pass the end_cursor of a previous result as cursor to fetch the next page.
  • skip_truncation disables the Agents API's default truncation of large payloads.
  • intent is a free-text description of why the action is being run, which some connectors use to refine results.

The download action is rejected, because it returns a binary stream and PyAirbyte does not yet support streaming responses.

def list_entities( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, **kwargs: Any) -> AgentExecuteResult:
232    def list_entities(
233        self,
234        entity_type: str,
235        api_args: dict[str, Any] | None = None,
236        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
237    ) -> AgentExecuteResult:
238        """Run the `list` action, which returns a page of entities of `entity_type`."""
239        return self.execute(entity_type, "list", api_args, **kwargs)

Run the list action, which returns a page of entities of entity_type.

def iter_entities( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, *, limit: int | None = None, **kwargs: Any) -> Iterator[dict[str, typing.Any]]:
241    def iter_entities(
242        self,
243        entity_type: str,
244        api_args: dict[str, Any] | None = None,
245        *,
246        limit: int | None = None,
247        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `list_entities()`.
248    ) -> Iterator[dict[str, Any]]:
249        """Yield entities of `entity_type`, following the connector's pagination cursor.
250
251        This is the pagination-free way to read entities: each page is fetched lazily as
252        the caller iterates, so no cursor bookkeeping is needed.
253
254        ```python
255        for issue in connector.iter_entities("issues", {"repository": "airbytehq/PyAirbyte"}):
256            print(issue["title"])
257        ```
258
259        `limit` caps how many entities are yielded in total, which matters for entity types
260        with no natural end. Pass `page_size` to control how many are fetched per request.
261
262        Iteration stops early if the connector reports another page without advancing its
263        cursor, rather than requesting the same page forever.
264
265        Use `list_entities()` instead when a single page is enough, or when the result's
266        `status`, `warning`, or `execution_metadata` are needed.
267        """
268        cursor: str | None = kwargs.pop("cursor", None)
269        seen_cursors: set[str] = set()
270        yielded = 0
271
272        while True:
273            result = self.list_entities(entity_type, api_args, cursor=cursor, **kwargs)
274            for agent_entity in result.entities:
275                yield agent_entity
276                yielded += 1
277                if limit is not None and yielded >= limit:
278                    return
279
280            cursor = result.end_cursor
281            if not result.has_next_page or cursor is None or cursor in seen_cursors:
282                return
283            seen_cursors.add(cursor)

Yield entities of entity_type, following the connector's pagination cursor.

This is the pagination-free way to read entities: each page is fetched lazily as the caller iterates, so no cursor bookkeeping is needed.

for issue in connector.iter_entities("issues", {"repository": "airbytehq/PyAirbyte"}):
    print(issue["title"])

limit caps how many entities are yielded in total, which matters for entity types with no natural end. Pass page_size to control how many are fetched per request.

Iteration stops early if the connector reports another page without advancing its cursor, rather than requesting the same page forever.

Use list_entities() instead when a single page is enough, or when the result's status, warning, or execution_metadata are needed.

def search_entities( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, **kwargs: Any) -> AgentExecuteResult:
285    def search_entities(
286        self,
287        entity_type: str,
288        api_args: dict[str, Any] | None = None,
289        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
290    ) -> AgentExecuteResult:
291        """Run the `search` action, which returns matching entities of `entity_type`."""
292        return self.execute(entity_type, "search", api_args, **kwargs)

Run the search action, which returns matching entities of entity_type.

def get_entity( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, **kwargs: Any) -> AgentExecuteResult:
294    def get_entity(
295        self,
296        entity_type: str,
297        api_args: dict[str, Any] | None = None,
298        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
299    ) -> AgentExecuteResult:
300        """Run the `get` action, which returns a single entity of `entity_type`."""
301        return self.execute(entity_type, "get", api_args, **kwargs)

Run the get action, which returns a single entity of entity_type.

def create_entity( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, **kwargs: Any) -> AgentExecuteResult:
303    def create_entity(
304        self,
305        entity_type: str,
306        api_args: dict[str, Any] | None = None,
307        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
308    ) -> AgentExecuteResult:
309        """Run the `create` action, which creates an entity of `entity_type`."""
310        return self.execute(entity_type, "create", api_args, **kwargs)

Run the create action, which creates an entity of entity_type.

def update_entity( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, **kwargs: Any) -> AgentExecuteResult:
312    def update_entity(
313        self,
314        entity_type: str,
315        api_args: dict[str, Any] | None = None,
316        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
317    ) -> AgentExecuteResult:
318        """Run the `update` action, which updates an entity of `entity_type`."""
319        return self.execute(entity_type, "update", api_args, **kwargs)

Run the update action, which updates an entity of entity_type.

def delete_entity( self, entity_type: str, api_args: dict[str, typing.Any] | None = None, **kwargs: Any) -> AgentExecuteResult:
321    def delete_entity(
322        self,
323        entity_type: str,
324        api_args: dict[str, Any] | None = None,
325        **kwargs: Any,  # noqa: ANN401  # Forwarded verbatim to `execute()`.
326    ) -> AgentExecuteResult:
327        """Run the `delete` action, which deletes an entity of `entity_type`."""
328        return self.execute(entity_type, "delete", api_args, **kwargs)

Run the delete action, which deletes an entity of entity_type.

class AgentConnectorDetails(pydantic.main.BaseModel):
 72class AgentConnectorDetails(BaseModel):
 73    """Connector metadata returned by the Agents API `inspect` endpoint."""
 74
 75    model_config = ConfigDict(extra="allow")
 76
 77    connector_id: str
 78    """The connector ID."""
 79
 80    name: str | None = None
 81    """The connector name."""
 82
 83    workspace_id: str | None = None
 84    """The ID of the workspace the connector belongs to."""
 85
 86    organization_id: str | None = None
 87    """The ID of the organization the connector belongs to."""
 88
 89    source_definition_id: str | None = None
 90    """The ID of the underlying Airbyte source definition."""
 91
 92    source_definition_name: str | None = None
 93    """The name of the underlying Airbyte source definition, for example `GitHub`."""
 94
 95    context_store_readiness: AgentContextStoreReadiness | None = None
 96    """Context Store readiness information, when reported."""
 97
 98    warnings: list[Any] = Field(default_factory=list)
 99    """Warnings reported by the Agents API, for example degraded capabilities."""
100
101    @property
102    def context_store_entities(self) -> list[str]:
103        """The entity names this connector can cache in the Context Store.
104
105        Note that this lists Context Store-supported entities specifically. The Agents API
106        does not publish an exhaustive list of executable entity and action pairs, so an
107        entity may be executable via `AgentConnector.execute()` without appearing here.
108        """
109        if self.context_store_readiness is None:
110            return []
111        return [
112            entity.entity
113            for entity in self.context_store_readiness.supported_context_store_entities
114        ]

Connector metadata returned by the Agents API inspect endpoint.

connector_id: str = PydanticUndefined

The connector ID.

name: str | None = None

The connector name.

workspace_id: str | None = None

The ID of the workspace the connector belongs to.

organization_id: str | None = None

The ID of the organization the connector belongs to.

source_definition_id: str | None = None

The ID of the underlying Airbyte source definition.

source_definition_name: str | None = None

The name of the underlying Airbyte source definition, for example GitHub.

context_store_readiness: AgentContextStoreReadiness | None = None

Context Store readiness information, when reported.

warnings: list[typing.Any] = PydanticUndefined

Warnings reported by the Agents API, for example degraded capabilities.

context_store_entities: list[str]
101    @property
102    def context_store_entities(self) -> list[str]:
103        """The entity names this connector can cache in the Context Store.
104
105        Note that this lists Context Store-supported entities specifically. The Agents API
106        does not publish an exhaustive list of executable entity and action pairs, so an
107        entity may be executable via `AgentConnector.execute()` without appearing here.
108        """
109        if self.context_store_readiness is None:
110            return []
111        return [
112            entity.entity
113            for entity in self.context_store_readiness.supported_context_store_entities
114        ]

The entity names this connector can cache in the Context Store.

Note that this lists Context Store-supported entities specifically. The Agents API does not publish an exhaustive list of executable entity and action pairs, so an entity may be executable via AgentConnector.execute() without appearing here.

class AgentConnectorInfo(pydantic.main.BaseModel):
36class AgentConnectorInfo(BaseModel):
37    """Summary information about a connector, as returned by the Agents API."""
38
39    model_config = ConfigDict(extra="allow")
40
41    id: str
42    """The connector ID."""
43
44    name: str | None = None
45    """The connector name, for example `GitHub - <workspace_id>`."""

Summary information about a connector, as returned by the Agents API.

id: str = PydanticUndefined

The connector ID.

name: str | None = None

The connector name, for example GitHub - <workspace_id>.

class AgentConnectorMetadata(pydantic.main.BaseModel):
129class AgentConnectorMetadata(BaseModel):
130    """Connector-reported metadata about a single action's result, including pagination."""
131
132    model_config = ConfigDict(extra="allow")
133
134    has_next_page: bool | None = None
135    """Whether more entities are available after this page, when the connector reports it."""
136
137    end_cursor: str | None = None
138    """The cursor to pass as `cursor` to fetch the next page, when one is available."""

Connector-reported metadata about a single action's result, including pagination.

has_next_page: bool | None = None

Whether more entities are available after this page, when the connector reports it.

end_cursor: str | None = None

The cursor to pass as cursor to fetch the next page, when one is available.

class AgentContextStoreEntity(pydantic.main.BaseModel):
48class AgentContextStoreEntity(BaseModel):
49    """An entity that a connector supports caching in the Airbyte Context Store."""
50
51    model_config = ConfigDict(extra="allow")
52
53    entity: str
54    """The entity name, for example `issues`."""
55
56    suggested: bool | None = None
57    """Whether Airbyte suggests caching this entity."""

An entity that a connector supports caching in the Airbyte Context Store.

entity: str = PydanticUndefined

The entity name, for example issues.

suggested: bool | None = None

Whether Airbyte suggests caching this entity.

class AgentContextStoreReadiness(pydantic.main.BaseModel):
60class AgentContextStoreReadiness(BaseModel):
61    """Context Store readiness information for a connector."""
62
63    model_config = ConfigDict(extra="allow")
64
65    supported_context_store_entities: list[AgentContextStoreEntity] = Field(default_factory=list)
66    """The entities this connector can cache in the Context Store."""
67
68    configured_cache_entities: list[dict[str, Any]] = Field(default_factory=list)
69    """The entities currently configured for caching, with their sync status."""

Context Store readiness information for a connector.

supported_context_store_entities: list[AgentContextStoreEntity] = PydanticUndefined

The entities this connector can cache in the Context Store.

configured_cache_entities: list[dict[str, typing.Any]] = PydanticUndefined

The entities currently configured for caching, with their sync status.

class AgentExecuteResult(pydantic.main.BaseModel):
141class AgentExecuteResult(BaseModel):
142    """The result of executing a single action against an Airbyte Agents connector."""
143
144    model_config = ConfigDict(extra="allow")
145
146    status: str
147    """The execution status reported by the Agents API, for example `success`."""
148
149    result: Any = None
150    """The action's payload. Entity-returning actions put a list of entities here."""
151
152    connector_metadata: AgentConnectorMetadata = Field(default_factory=AgentConnectorMetadata)
153    """Connector-reported metadata about the result, including pagination cursors."""
154
155    execution_metadata: AgentExecutionMetadata = Field(default_factory=AgentExecutionMetadata)
156    """Metadata describing how the action was executed."""
157
158    warning: dict[str, Any] | None = None
159    """A warning reported alongside an otherwise successful result."""
160
161    @property
162    def entities(self) -> list[dict[str, Any]]:
163        """The result as a list of entities.
164
165        Raises `PyAirbyteInputError` if the action did not return a list of entities. Use
166        `result` for actions whose payload is not a list of entities.
167        """
168        if not isinstance(self.result, list):
169            raise PyAirbyteInputError(
170                message="This action did not return a list of entities.",
171                guidance="Use the `result` attribute to read non-entity result payloads.",
172                context={"result_type": type(self.result).__name__},
173            )
174
175        invalid_types = sorted(
176            {type(entity).__name__ for entity in self.result if not isinstance(entity, dict)}
177        )
178        if invalid_types:
179            raise PyAirbyteInputError(
180                message="This action returned a list that is not a list of entities.",
181                guidance="Use the `result` attribute to read non-entity result payloads.",
182                context={"unexpected_item_types": invalid_types},
183            )
184        return self.result
185
186    @property
187    def has_next_page(self) -> bool:
188        """Whether the connector reported more entities after this page."""
189        return bool(self.connector_metadata.has_next_page)
190
191    @property
192    def end_cursor(self) -> str | None:
193        """The cursor for the next page, or `None` when there is no next page."""
194        return self.connector_metadata.end_cursor

The result of executing a single action against an Airbyte Agents connector.

status: str = PydanticUndefined

The execution status reported by the Agents API, for example success.

result: Any = None

The action's payload. Entity-returning actions put a list of entities here.

connector_metadata: AgentConnectorMetadata = PydanticUndefined

Connector-reported metadata about the result, including pagination cursors.

execution_metadata: AgentExecutionMetadata = PydanticUndefined

Metadata describing how the action was executed.

warning: dict[str, typing.Any] | None = None

A warning reported alongside an otherwise successful result.

entities: list[dict[str, typing.Any]]
161    @property
162    def entities(self) -> list[dict[str, Any]]:
163        """The result as a list of entities.
164
165        Raises `PyAirbyteInputError` if the action did not return a list of entities. Use
166        `result` for actions whose payload is not a list of entities.
167        """
168        if not isinstance(self.result, list):
169            raise PyAirbyteInputError(
170                message="This action did not return a list of entities.",
171                guidance="Use the `result` attribute to read non-entity result payloads.",
172                context={"result_type": type(self.result).__name__},
173            )
174
175        invalid_types = sorted(
176            {type(entity).__name__ for entity in self.result if not isinstance(entity, dict)}
177        )
178        if invalid_types:
179            raise PyAirbyteInputError(
180                message="This action returned a list that is not a list of entities.",
181                guidance="Use the `result` attribute to read non-entity result payloads.",
182                context={"unexpected_item_types": invalid_types},
183            )
184        return self.result

The result as a list of entities.

Raises PyAirbyteInputError if the action did not return a list of entities. Use result for actions whose payload is not a list of entities.

has_next_page: bool
186    @property
187    def has_next_page(self) -> bool:
188        """Whether the connector reported more entities after this page."""
189        return bool(self.connector_metadata.has_next_page)

Whether the connector reported more entities after this page.

end_cursor: str | None
191    @property
192    def end_cursor(self) -> str | None:
193        """The cursor for the next page, or `None` when there is no next page."""
194        return self.connector_metadata.end_cursor

The cursor for the next page, or None when there is no next page.

class AgentExecutionMetadata(pydantic.main.BaseModel):
117class AgentExecutionMetadata(BaseModel):
118    """Metadata describing how an Agents connector action was executed."""
119
120    model_config = ConfigDict(extra="allow")
121
122    connector_instance_id: str | None = None
123    """The connector instance that served the request."""
124
125    execution_time_ms: int | None = None
126    """The server-side execution time, in milliseconds."""

Metadata describing how an Agents connector action was executed.

connector_instance_id: str | None = None

The connector instance that served the request.

execution_time_ms: int | None = None

The server-side execution time, in milliseconds.

class AgentOrganization:
 70class AgentOrganization:
 71    """An organization on the Airbyte Agents platform.
 72
 73    ```python
 74    from airbyte import agents
 75
 76    organization = agents.AgentOrganization.from_env()
 77    workspace = organization.get_workspace("my-workspace")  # by ID or name (case insensitive)
 78    ```
 79    """
 80
 81    def __init__(
 82        self,
 83        *,
 84        organization_id: str | None = None,
 85        client_id: str | SecretString | None = None,
 86        client_secret: str | SecretString | None = None,
 87        bearer_token: str | SecretString | None = None,
 88    ) -> None:
 89        """Initialize an `AgentOrganization`.
 90
 91        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
 92        not passed explicitly. The organization ID is optional: the Agents API infers it
 93        when the credentials belong to exactly one organization.
 94        """
 95        self._credentials = _AirbyteCredentials.from_auth(
 96            organization_id=organization_id,
 97            client_id=client_id,
 98            client_secret=client_secret,
 99            bearer_token=bearer_token,
100            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
101            # fallback, since an env bearer token plus explicit client creds is rejected
102            # as mutually exclusive auth.
103            env_vars=not (client_id or client_secret or bearer_token),
104        )
105
106        self.organization_id: str | None = self._credentials.organization_id
107        """The organization ID, when known."""
108
109    @classmethod
110    def from_env(cls, organization_id: str | None = None) -> AgentOrganization:
111        """Create an `AgentOrganization` from the `AIRBYTE_CLOUD_*` environment variables."""
112        return cls(organization_id=organization_id)
113
114    def list_workspaces(self) -> list[AgentWorkspace]:
115        """List the workspaces visible to these credentials in the Agents API."""
116        return [
117            self._workspace_from_info(info)
118            for info in (
119                AgentWorkspaceInfo.model_validate(record)
120                for record in _api_util.list_agent_workspaces(
121                    credentials=self._credentials,
122                    organization_id=self.organization_id,
123                )
124            )
125        ]
126
127    def get_workspace(
128        self,
129        id_or_name: str | None = None,
130        /,
131        *,
132        workspace_id: str | None = None,
133        name: str | None = None,
134    ) -> AgentWorkspace:
135        """Get a workspace in this organization, by ID or by name.
136
137        Pass a single positional value to look the workspace up by either its ID or its
138        name, or name the argument to be explicit.
139
140        Lookup by an explicit `workspace_id` does not call the Agents API. Every other form
141        lists the organization's workspaces and matches on ID first, then on an exact name,
142        ignoring case.
143        """
144        lookup = _resolve_workspace_lookup(
145            id_or_name,
146            workspace_id=workspace_id,
147            name=name,
148        )
149
150        if lookup.workspace_id and not lookup.name:
151            return self._workspace_from_info(AgentWorkspaceInfo(id=lookup.workspace_id))
152
153        workspaces = self.list_workspaces()
154        if lookup.workspace_id:
155            id_matches = [
156                workspace
157                for workspace in workspaces
158                if workspace.workspace_id == lookup.workspace_id
159            ]
160            if id_matches:
161                return id_matches[0]
162
163        name_lower = (lookup.name or "").lower()
164        matches = [
165            workspace
166            for workspace in workspaces
167            if workspace.name and workspace.name.lower() == name_lower
168        ]
169        if not matches:
170            raise AirbyteError(
171                message="No workspace found with the given ID or name.",
172                guidance="Use `list_workspaces()` to see the available workspaces.",
173                context={"name": lookup.name},
174            )
175        if len(matches) > 1:
176            raise AirbyteError(
177                message="Multiple workspaces matched the given name.",
178                guidance="Pass `workspace_id` instead of `name`.",
179                context={"name": lookup.name, "match_count": len(matches)},
180            )
181        return matches[0]
182
183    def as_cloud_organization(self) -> CloudOrganization:
184        """Return this organization as an `airbyte.cloud.CloudOrganization`.
185
186        Every Agents organization is also a Cloud organization, so this conversion needs no
187        API call. It requires a known organization ID, and raises `PyAirbyteInputError`
188        when the ID is unknown.
189        """
190        if not self.organization_id:
191            raise PyAirbyteInputError(
192                message="Organization ID is required to convert to a `CloudOrganization`.",
193                guidance=(
194                    "Provide `organization_id`, or set the `AIRBYTE_CLOUD_ORGANIZATION_ID` "
195                    "environment variable."
196                ),
197            )
198        return CloudOrganization(
199            organization_id=self.organization_id,
200            client_id=self._credentials.client_id,
201            client_secret=self._credentials.client_secret,
202            bearer_token=self._credentials.bearer_token,
203            public_api_root=self._credentials.public_api_root,
204            config_api_root=self._credentials.config_api_root,
205        )
206
207    @classmethod
208    def from_cloud_organization(
209        cls,
210        cloud_organization: CloudOrganization,
211    ) -> AgentOrganization:
212        """Return a Cloud organization as an `AgentOrganization`.
213
214        Whether the organization can actually execute connector actions depends on its
215        Airbyte Agents subscription, which is only knowable per workspace. Use
216        `AgentWorkspace.from_cloud_workspace()` for an authoritative eligibility check.
217
218        Raises `PyAirbyteInputError` when the Cloud organization uses non-public Cloud API
219        roots, since an `AgentOrganization` cannot carry them.
220        """
221        credentials = cloud_organization._credentials  # noqa: SLF001  # Same-domain conversion.
222        _api_util.check_public_cloud_api_roots(credentials)
223        return cls(
224            organization_id=cloud_organization.organization_id,
225            client_id=credentials.client_id,
226            client_secret=credentials.client_secret,
227            bearer_token=credentials.bearer_token,
228        )
229
230    def _workspace_from_info(self, info: AgentWorkspaceInfo) -> AgentWorkspace:
231        """Build an `AgentWorkspace` from workspace info, reusing these credentials."""
232        return AgentWorkspace(
233            workspace_id=info.id,
234            organization_id=info.organization_id or self.organization_id,
235            name=info.name,
236            client_id=self._credentials.client_id,
237            client_secret=self._credentials.client_secret,
238            bearer_token=self._credentials.bearer_token,
239        )

An organization on the Airbyte Agents platform.

from airbyte import agents

organization = agents.AgentOrganization.from_env()
workspace = organization.get_workspace("my-workspace")  # by ID or name (case insensitive)
AgentOrganization( *, organization_id: 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)
 81    def __init__(
 82        self,
 83        *,
 84        organization_id: str | None = None,
 85        client_id: str | SecretString | None = None,
 86        client_secret: str | SecretString | None = None,
 87        bearer_token: str | SecretString | None = None,
 88    ) -> None:
 89        """Initialize an `AgentOrganization`.
 90
 91        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
 92        not passed explicitly. The organization ID is optional: the Agents API infers it
 93        when the credentials belong to exactly one organization.
 94        """
 95        self._credentials = _AirbyteCredentials.from_auth(
 96            organization_id=organization_id,
 97            client_id=client_id,
 98            client_secret=client_secret,
 99            bearer_token=bearer_token,
100            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
101            # fallback, since an env bearer token plus explicit client creds is rejected
102            # as mutually exclusive auth.
103            env_vars=not (client_id or client_secret or bearer_token),
104        )
105
106        self.organization_id: str | None = self._credentials.organization_id
107        """The organization ID, when known."""

Initialize an AgentOrganization.

Credentials fall back to the AIRBYTE_CLOUD_* environment variables when they are not passed explicitly. The organization ID is optional: the Agents API infers it when the credentials belong to exactly one organization.

organization_id: str | None

The organization ID, when known.

@classmethod
def from_env( cls, organization_id: str | None = None) -> AgentOrganization:
109    @classmethod
110    def from_env(cls, organization_id: str | None = None) -> AgentOrganization:
111        """Create an `AgentOrganization` from the `AIRBYTE_CLOUD_*` environment variables."""
112        return cls(organization_id=organization_id)

Create an AgentOrganization from the AIRBYTE_CLOUD_* environment variables.

def list_workspaces(self) -> list[AgentWorkspace]:
114    def list_workspaces(self) -> list[AgentWorkspace]:
115        """List the workspaces visible to these credentials in the Agents API."""
116        return [
117            self._workspace_from_info(info)
118            for info in (
119                AgentWorkspaceInfo.model_validate(record)
120                for record in _api_util.list_agent_workspaces(
121                    credentials=self._credentials,
122                    organization_id=self.organization_id,
123                )
124            )
125        ]

List the workspaces visible to these credentials in the Agents API.

def get_workspace( self, id_or_name: str | None = None, /, *, workspace_id: str | None = None, name: str | None = None) -> AgentWorkspace:
127    def get_workspace(
128        self,
129        id_or_name: str | None = None,
130        /,
131        *,
132        workspace_id: str | None = None,
133        name: str | None = None,
134    ) -> AgentWorkspace:
135        """Get a workspace in this organization, by ID or by name.
136
137        Pass a single positional value to look the workspace up by either its ID or its
138        name, or name the argument to be explicit.
139
140        Lookup by an explicit `workspace_id` does not call the Agents API. Every other form
141        lists the organization's workspaces and matches on ID first, then on an exact name,
142        ignoring case.
143        """
144        lookup = _resolve_workspace_lookup(
145            id_or_name,
146            workspace_id=workspace_id,
147            name=name,
148        )
149
150        if lookup.workspace_id and not lookup.name:
151            return self._workspace_from_info(AgentWorkspaceInfo(id=lookup.workspace_id))
152
153        workspaces = self.list_workspaces()
154        if lookup.workspace_id:
155            id_matches = [
156                workspace
157                for workspace in workspaces
158                if workspace.workspace_id == lookup.workspace_id
159            ]
160            if id_matches:
161                return id_matches[0]
162
163        name_lower = (lookup.name or "").lower()
164        matches = [
165            workspace
166            for workspace in workspaces
167            if workspace.name and workspace.name.lower() == name_lower
168        ]
169        if not matches:
170            raise AirbyteError(
171                message="No workspace found with the given ID or name.",
172                guidance="Use `list_workspaces()` to see the available workspaces.",
173                context={"name": lookup.name},
174            )
175        if len(matches) > 1:
176            raise AirbyteError(
177                message="Multiple workspaces matched the given name.",
178                guidance="Pass `workspace_id` instead of `name`.",
179                context={"name": lookup.name, "match_count": len(matches)},
180            )
181        return matches[0]

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

Pass a single positional value to look the workspace up by either its ID or its name, or name the argument to be explicit.

Lookup by an explicit workspace_id does not call the Agents API. Every other form lists the organization's workspaces and matches on ID first, then on an exact name, ignoring case.

def as_cloud_organization(self) -> airbyte.cloud.CloudOrganization:
183    def as_cloud_organization(self) -> CloudOrganization:
184        """Return this organization as an `airbyte.cloud.CloudOrganization`.
185
186        Every Agents organization is also a Cloud organization, so this conversion needs no
187        API call. It requires a known organization ID, and raises `PyAirbyteInputError`
188        when the ID is unknown.
189        """
190        if not self.organization_id:
191            raise PyAirbyteInputError(
192                message="Organization ID is required to convert to a `CloudOrganization`.",
193                guidance=(
194                    "Provide `organization_id`, or set the `AIRBYTE_CLOUD_ORGANIZATION_ID` "
195                    "environment variable."
196                ),
197            )
198        return CloudOrganization(
199            organization_id=self.organization_id,
200            client_id=self._credentials.client_id,
201            client_secret=self._credentials.client_secret,
202            bearer_token=self._credentials.bearer_token,
203            public_api_root=self._credentials.public_api_root,
204            config_api_root=self._credentials.config_api_root,
205        )

Return this organization as an airbyte.cloud.CloudOrganization.

Every Agents organization is also a Cloud organization, so this conversion needs no API call. It requires a known organization ID, and raises PyAirbyteInputError when the ID is unknown.

@classmethod
def from_cloud_organization( cls, cloud_organization: airbyte.cloud.CloudOrganization) -> AgentOrganization:
207    @classmethod
208    def from_cloud_organization(
209        cls,
210        cloud_organization: CloudOrganization,
211    ) -> AgentOrganization:
212        """Return a Cloud organization as an `AgentOrganization`.
213
214        Whether the organization can actually execute connector actions depends on its
215        Airbyte Agents subscription, which is only knowable per workspace. Use
216        `AgentWorkspace.from_cloud_workspace()` for an authoritative eligibility check.
217
218        Raises `PyAirbyteInputError` when the Cloud organization uses non-public Cloud API
219        roots, since an `AgentOrganization` cannot carry them.
220        """
221        credentials = cloud_organization._credentials  # noqa: SLF001  # Same-domain conversion.
222        _api_util.check_public_cloud_api_roots(credentials)
223        return cls(
224            organization_id=cloud_organization.organization_id,
225            client_id=credentials.client_id,
226            client_secret=credentials.client_secret,
227            bearer_token=credentials.bearer_token,
228        )

Return a Cloud organization as an AgentOrganization.

Whether the organization can actually execute connector actions depends on its Airbyte Agents subscription, which is only knowable per workspace. Use AgentWorkspace.from_cloud_workspace() for an authoritative eligibility check.

Raises PyAirbyteInputError when the Cloud organization uses non-public Cloud API roots, since an AgentOrganization cannot carry them.

class AgentWorkspace:
 21class AgentWorkspace:
 22    """A workspace on the Airbyte Agents platform.
 23
 24    Airbyte Cloud credentials authenticate against the Agents API, so this class reads the
 25    same `AIRBYTE_CLOUD_*` environment variables as `airbyte.cloud.CloudWorkspace`.
 26
 27    ```python
 28    from airbyte import agents
 29
 30    workspace = agents.AgentWorkspace.from_env()
 31    for connector in workspace.list_connectors():
 32        print(connector.name)
 33    ```
 34    """
 35
 36    def __init__(
 37        self,
 38        *,
 39        workspace_id: str | None = None,
 40        organization_id: str | None = None,
 41        name: str | None = None,
 42        client_id: str | SecretString | None = None,
 43        client_secret: str | SecretString | None = None,
 44        bearer_token: str | SecretString | None = None,
 45    ) -> None:
 46        """Initialize an `AgentWorkspace`.
 47
 48        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
 49        not passed explicitly.
 50        """
 51        credentials = _AirbyteCredentials.from_auth(
 52            workspace_id=workspace_id,
 53            organization_id=organization_id,
 54            client_id=client_id,
 55            client_secret=client_secret,
 56            bearer_token=bearer_token,
 57            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
 58            # fallback, since an env bearer token plus explicit client creds is rejected
 59            # as mutually exclusive auth.
 60            env_vars=not (client_id or client_secret or bearer_token),
 61        )
 62        if not credentials.workspace_id:
 63            raise PyAirbyteInputError(
 64                message="Workspace ID is required.",
 65                guidance=(
 66                    "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` "
 67                    "environment variable."
 68                ),
 69            )
 70
 71        self._credentials = credentials
 72
 73        self.workspace_id: str = credentials.workspace_id
 74        """The workspace ID."""
 75
 76        self.organization_id: str | None = credentials.organization_id
 77        """The organization ID, sent to the Agents API when it is known."""
 78
 79        self.name: str | None = name
 80        """The workspace name, when known. Use `get_info()` to fetch it from the API."""
 81
 82    @classmethod
 83    def from_env(
 84        cls,
 85        workspace_id: str | None = None,
 86        *,
 87        organization_id: str | None = None,
 88    ) -> AgentWorkspace:
 89        """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables.
 90
 91        The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the
 92        `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with
 93        `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`.
 94        """
 95        return cls(workspace_id=workspace_id, organization_id=organization_id)
 96
 97    def get_info(self) -> AgentWorkspaceInfo:
 98        """Fetch this workspace from the Agents API.
 99
100        A successful call is authoritative proof that the workspace is reachable through
101        the Agents API with these credentials.
102        """
103        return AgentWorkspaceInfo.model_validate(
104            _api_util.get_agent_workspace(
105                workspace_id=self.workspace_id,
106                credentials=self._credentials,
107                organization_id=self.organization_id,
108            )
109        )
110
111    def list_connectors(self) -> list[AgentConnector]:
112        """List the connectors configured in this workspace."""
113        return [
114            AgentConnector(
115                connector_id=info.id,
116                name=info.name,
117                credentials=self._credentials,
118            )
119            for info in (
120                AgentConnectorInfo.model_validate(record)
121                for record in _api_util.list_agent_connectors(
122                    workspace_id=self.workspace_id,
123                    credentials=self._credentials,
124                    organization_id=self.organization_id,
125                )
126            )
127        ]
128
129    def get_connector(
130        self,
131        id_or_name: str | None = None,
132        /,
133        *,
134        id: str | None = None,  # noqa: A002  # Shadows `id` deliberately, as a short alias.
135        connector_id: str | None = None,
136        name: str | None = None,
137    ) -> AgentConnector:
138        """Get a connector in this workspace, by ID or by name.
139
140        Pass a single positional value to look the connector up by either its ID or its
141        name, or name the argument to be explicit: `id` and `connector_id` are synonyms,
142        so pass whichever reads better.
143
144        Lookup by an explicit ID does not call the Agents API. Every other form lists the
145        workspace's connectors and matches on ID first, then on an exact name, then on a
146        unique substring, so `name="GitHub"` finds a connector named
147        `GitHub - <workspace_id>`. Name matching is case-insensitive.
148        """
149        lookup = _resolve_connector_lookup(
150            id_or_name,
151            id=id,
152            connector_id=connector_id,
153            name=name,
154        )
155
156        if lookup.connector_id and not lookup.name:
157            return AgentConnector(connector_id=lookup.connector_id, credentials=self._credentials)
158
159        connectors = self.list_connectors()
160        if lookup.connector_id:
161            id_matches = [
162                connector
163                for connector in connectors
164                if connector.connector_id == lookup.connector_id
165            ]
166            if id_matches:
167                return id_matches[0]
168
169        name_lower = (lookup.name or "").lower()
170        matches = [
171            connector
172            for connector in connectors
173            if connector.name and connector.name.lower() == name_lower
174        ] or [
175            connector
176            for connector in connectors
177            if connector.name and name_lower in connector.name.lower()
178        ]
179        if not matches:
180            raise AirbyteError(
181                message="No connector found with the given ID or name.",
182                guidance="Use `list_connectors()` to see the available connectors.",
183                context={"lookup": lookup.name, "workspace_id": self.workspace_id},
184            )
185        if len(matches) > 1:
186            raise AirbyteError(
187                message="Multiple connectors matched the given name.",
188                guidance="Pass `connector_id`, or a name that matches only one connector.",
189                context={
190                    "name": lookup.name,
191                    "matched_names": [connector.name for connector in matches],
192                },
193            )
194        return matches[0]
195
196    def as_cloud_workspace(self) -> CloudWorkspace:
197        """Return this workspace as an `airbyte.cloud.CloudWorkspace`.
198
199        Every Agents workspace is also a Cloud workspace, so this conversion always
200        succeeds without calling either API.
201        """
202        return CloudWorkspace(
203            workspace_id=self.workspace_id,
204            client_id=self._credentials.client_id,
205            client_secret=self._credentials.client_secret,
206            bearer_token=self._credentials.bearer_token,
207            api_root=self._credentials.public_api_root,
208            config_api_root=self._credentials.config_api_root,
209        )
210
211    @classmethod
212    def from_cloud_workspace(
213        cls,
214        cloud_workspace: CloudWorkspace,
215        *,
216        organization_id: str | None = None,
217        verify: bool = True,
218    ) -> AgentWorkspace:
219        """Return a Cloud workspace as an `AgentWorkspace`.
220
221        Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is
222        reachable through the Agents API: the organization needs an Airbyte Agents
223        subscription. By default this is verified by fetching the workspace from the Agents
224        API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to
225        skip that call.
226
227        Raises `PyAirbyteInputError` when the Cloud workspace uses non-public Cloud API
228        roots, since an `AgentWorkspace` cannot carry them.
229        """
230        _api_util.check_public_cloud_api_roots(
231            cloud_workspace._credentials,  # noqa: SLF001  # Same-domain conversion.
232        )
233        workspace = cls(
234            workspace_id=cloud_workspace.workspace_id,
235            organization_id=organization_id,
236            client_id=cloud_workspace.client_id,
237            client_secret=cloud_workspace.client_secret,
238            bearer_token=cloud_workspace.bearer_token,
239        )
240        if verify:
241            workspace.get_info()
242        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)
36    def __init__(
37        self,
38        *,
39        workspace_id: str | None = None,
40        organization_id: str | None = None,
41        name: str | None = None,
42        client_id: str | SecretString | None = None,
43        client_secret: str | SecretString | None = None,
44        bearer_token: str | SecretString | None = None,
45    ) -> None:
46        """Initialize an `AgentWorkspace`.
47
48        Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are
49        not passed explicitly.
50        """
51        credentials = _AirbyteCredentials.from_auth(
52            workspace_id=workspace_id,
53            organization_id=organization_id,
54            client_id=client_id,
55            client_secret=client_secret,
56            bearer_token=bearer_token,
57            # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env
58            # fallback, since an env bearer token plus explicit client creds is rejected
59            # as mutually exclusive auth.
60            env_vars=not (client_id or client_secret or bearer_token),
61        )
62        if not credentials.workspace_id:
63            raise PyAirbyteInputError(
64                message="Workspace ID is required.",
65                guidance=(
66                    "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` "
67                    "environment variable."
68                ),
69            )
70
71        self._credentials = credentials
72
73        self.workspace_id: str = credentials.workspace_id
74        """The workspace ID."""
75
76        self.organization_id: str | None = credentials.organization_id
77        """The organization ID, sent to the Agents API when it is known."""
78
79        self.name: str | None = name
80        """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.

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:
82    @classmethod
83    def from_env(
84        cls,
85        workspace_id: str | None = None,
86        *,
87        organization_id: str | None = None,
88    ) -> AgentWorkspace:
89        """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables.
90
91        The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the
92        `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with
93        `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`.
94        """
95        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) -> AgentWorkspaceInfo:
 97    def get_info(self) -> AgentWorkspaceInfo:
 98        """Fetch this workspace from the Agents API.
 99
100        A successful call is authoritative proof that the workspace is reachable through
101        the Agents API with these credentials.
102        """
103        return AgentWorkspaceInfo.model_validate(
104            _api_util.get_agent_workspace(
105                workspace_id=self.workspace_id,
106                credentials=self._credentials,
107                organization_id=self.organization_id,
108            )
109        )

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[AgentConnector]:
111    def list_connectors(self) -> list[AgentConnector]:
112        """List the connectors configured in this workspace."""
113        return [
114            AgentConnector(
115                connector_id=info.id,
116                name=info.name,
117                credentials=self._credentials,
118            )
119            for info in (
120                AgentConnectorInfo.model_validate(record)
121                for record in _api_util.list_agent_connectors(
122                    workspace_id=self.workspace_id,
123                    credentials=self._credentials,
124                    organization_id=self.organization_id,
125                )
126            )
127        ]

List the connectors configured in this workspace.

def get_connector( self, id_or_name: str | None = None, /, *, id: str | None = None, connector_id: str | None = None, name: str | None = None) -> AgentConnector:
129    def get_connector(
130        self,
131        id_or_name: str | None = None,
132        /,
133        *,
134        id: str | None = None,  # noqa: A002  # Shadows `id` deliberately, as a short alias.
135        connector_id: str | None = None,
136        name: str | None = None,
137    ) -> AgentConnector:
138        """Get a connector in this workspace, by ID or by name.
139
140        Pass a single positional value to look the connector up by either its ID or its
141        name, or name the argument to be explicit: `id` and `connector_id` are synonyms,
142        so pass whichever reads better.
143
144        Lookup by an explicit ID does not call the Agents API. Every other form lists the
145        workspace's connectors and matches on ID first, then on an exact name, then on a
146        unique substring, so `name="GitHub"` finds a connector named
147        `GitHub - <workspace_id>`. Name matching is case-insensitive.
148        """
149        lookup = _resolve_connector_lookup(
150            id_or_name,
151            id=id,
152            connector_id=connector_id,
153            name=name,
154        )
155
156        if lookup.connector_id and not lookup.name:
157            return AgentConnector(connector_id=lookup.connector_id, credentials=self._credentials)
158
159        connectors = self.list_connectors()
160        if lookup.connector_id:
161            id_matches = [
162                connector
163                for connector in connectors
164                if connector.connector_id == lookup.connector_id
165            ]
166            if id_matches:
167                return id_matches[0]
168
169        name_lower = (lookup.name or "").lower()
170        matches = [
171            connector
172            for connector in connectors
173            if connector.name and connector.name.lower() == name_lower
174        ] or [
175            connector
176            for connector in connectors
177            if connector.name and name_lower in connector.name.lower()
178        ]
179        if not matches:
180            raise AirbyteError(
181                message="No connector found with the given ID or name.",
182                guidance="Use `list_connectors()` to see the available connectors.",
183                context={"lookup": lookup.name, "workspace_id": self.workspace_id},
184            )
185        if len(matches) > 1:
186            raise AirbyteError(
187                message="Multiple connectors matched the given name.",
188                guidance="Pass `connector_id`, or a name that matches only one connector.",
189                context={
190                    "name": lookup.name,
191                    "matched_names": [connector.name for connector in matches],
192                },
193            )
194        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:
196    def as_cloud_workspace(self) -> CloudWorkspace:
197        """Return this workspace as an `airbyte.cloud.CloudWorkspace`.
198
199        Every Agents workspace is also a Cloud workspace, so this conversion always
200        succeeds without calling either API.
201        """
202        return CloudWorkspace(
203            workspace_id=self.workspace_id,
204            client_id=self._credentials.client_id,
205            client_secret=self._credentials.client_secret,
206            bearer_token=self._credentials.bearer_token,
207            api_root=self._credentials.public_api_root,
208            config_api_root=self._credentials.config_api_root,
209        )

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:
211    @classmethod
212    def from_cloud_workspace(
213        cls,
214        cloud_workspace: CloudWorkspace,
215        *,
216        organization_id: str | None = None,
217        verify: bool = True,
218    ) -> AgentWorkspace:
219        """Return a Cloud workspace as an `AgentWorkspace`.
220
221        Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is
222        reachable through the Agents API: the organization needs an Airbyte Agents
223        subscription. By default this is verified by fetching the workspace from the Agents
224        API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to
225        skip that call.
226
227        Raises `PyAirbyteInputError` when the Cloud workspace uses non-public Cloud API
228        roots, since an `AgentWorkspace` cannot carry them.
229        """
230        _api_util.check_public_cloud_api_roots(
231            cloud_workspace._credentials,  # noqa: SLF001  # Same-domain conversion.
232        )
233        workspace = cls(
234            workspace_id=cloud_workspace.workspace_id,
235            organization_id=organization_id,
236            client_id=cloud_workspace.client_id,
237            client_secret=cloud_workspace.client_secret,
238            bearer_token=cloud_workspace.bearer_token,
239        )
240        if verify:
241            workspace.get_info()
242        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 PyAirbyteInputError when the Cloud workspace uses non-public Cloud API roots, since an AgentWorkspace cannot carry them.

class AgentWorkspaceInfo(pydantic.main.BaseModel):
18class AgentWorkspaceInfo(BaseModel):
19    """Summary information about a workspace, as returned by the Agents API."""
20
21    model_config = ConfigDict(extra="allow")
22
23    id: str
24    """The workspace ID."""
25
26    name: str | None = None
27    """The workspace name."""
28
29    organization_id: str | None = None
30    """The ID of the organization the workspace belongs to."""
31
32    status: str | None = None
33    """The workspace status, for example `active`."""

Summary information about a workspace, as returned by the Agents API.

id: str = PydanticUndefined

The workspace ID.

name: str | None = None

The workspace name.

organization_id: str | None = None

The ID of the organization the workspace belongs to.

status: str | None = None

The workspace status, for example active.