airbyte.agents
PyAirbyte classes and methods for the Airbyte Agents platform.
⚠️ 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.
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 the AIRBYTE_CLOUD_*
variables are reused. Set AIRBYTE_AGENTS_API_URL to override the Agents API root when
connecting through a proxy or local development endpoint.
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.inspect().integration_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> ## ⚠️ 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 10Airbyte Agents connectors expose read and write actions on individual entities, executed 11one action at a time, rather than the batch record replication that `airbyte.cloud` 12provides. This module is that interface. 13 14Airbyte Cloud credentials authenticate against the Agents API, so the `AIRBYTE_CLOUD_*` 15variables are reused. Set `AIRBYTE_AGENTS_API_URL` to override the Agents API root when 16connecting through a proxy or local development endpoint. 17 18## Usage Examples 19 20Read entities from a connector, paging automatically as you iterate: 21 22```python 23from airbyte import agents 24 25workspace = agents.AgentWorkspace.from_env() 26connector = workspace.get_connector("GitHub") # by ID or name (case insensitive) 27 28for issue in connector.iter_entities( 29 "issues", 30 api_args={"repository": "airbytehq/PyAirbyte"}, # Passthrough API args 31): 32 print(issue["title"]) 33``` 34 35Fetch a single page instead, when the result's status and metadata are needed: 36 37```python 38result = connector.list_entities( 39 "issues", 40 api_args={"repository": "airbytehq/PyAirbyte"}, 41 page_size=50, 42) 43print(result.status, result.has_next_page) 44for entity in result.entities: 45 print(entity["title"]) 46``` 47 48Pass `result.end_cursor` back as `cursor` to page through manually: 49 50```python 51cursor = None 52while True: 53 result = connector.list_entities( 54 "issues", 55 api_args={"repository": "airbytehq/PyAirbyte"}, 56 cursor=cursor, 57 ) 58 print(len(result.entities)) 59 if not result.has_next_page: 60 break 61 cursor = result.end_cursor 62``` 63 64Discover what a connector supports, and what an organization can reach: 65 66```python 67organization = agents.AgentOrganization.from_env() 68for workspace in organization.list_workspaces(): 69 print(workspace.workspace_id, workspace.name) 70 71print(connector.inspect().integration_name) 72``` 73 74Convert between the Cloud and Agents domains: 75 76```python 77from airbyte.cloud import CloudWorkspace 78 79cloud_workspace = CloudWorkspace.from_env() 80agent_workspace = agents.AgentWorkspace.from_cloud_workspace(cloud_workspace) 81back_to_cloud = agent_workspace.as_cloud_workspace() 82``` 83""" 84 85from __future__ import annotations 86 87from typing import TYPE_CHECKING 88 89from airbyte._direct_connectors.models import ( 90 AgentConnectorDetails, 91 AgentConnectorInfo, 92 AgentConnectorMetadata, 93 AgentContextStoreEntity, 94 AgentContextStoreReadiness, 95 AgentExecuteResult, 96 AgentExecutionMetadata, 97 AgentSkillDocs, 98 AgentSkillInfo, 99 AgentSkillList, 100 AgentSkillSection, 101 AgentWorkspaceInfo, 102) 103from airbyte.agents.connectors import AgentConnector 104from airbyte.agents.organizations import AgentOrganization 105from airbyte.agents.skills import AgentSkill 106from airbyte.agents.workspaces import AgentWorkspace 107 108 109# Submodules imported here for documentation reasons: https://github.com/mitmproxy/pdoc/issues/757 110if TYPE_CHECKING: 111 # ruff: noqa: TC004 112 from airbyte.agents import ( 113 connectors, 114 organizations, 115 skills, 116 workspaces, 117 ) 118 119 120__all__ = [ 121 # Submodules 122 "connectors", 123 "organizations", 124 "skills", 125 "workspaces", 126 # Classes 127 "AgentConnector", 128 "AgentConnectorDetails", 129 "AgentConnectorInfo", 130 "AgentConnectorMetadata", 131 "AgentContextStoreEntity", 132 "AgentContextStoreReadiness", 133 "AgentExecuteResult", 134 "AgentExecutionMetadata", 135 "AgentOrganization", 136 "AgentSkill", 137 "AgentSkillDocs", 138 "AgentSkillInfo", 139 "AgentSkillList", 140 "AgentSkillSection", 141 "AgentWorkspace", 142 "AgentWorkspaceInfo", 143]
35class AgentConnector: 36 """A connector in an Airbyte Agents workspace. 37 38 Get one from `AgentWorkspace.get_connector()` rather than constructing it directly. 39 40 ```python 41 from airbyte import agents 42 43 workspace = agents.AgentWorkspace.from_env() 44 connector = workspace.get_connector("GitHub") # by ID or name (case insensitive) 45 result = connector.list_entities("issues", api_args={"repository": "airbytehq/PyAirbyte"}) 46 for entity in result.entities: 47 print(entity["title"]) 48 ``` 49 """ 50 51 def __init__( 52 self, 53 connector_id: str, 54 *, 55 credentials: _AirbyteCredentials, 56 name: str | None = None, 57 workspace_id: str | None = None, 58 ) -> None: 59 """Initialize an `AgentConnector`. Prefer `AgentWorkspace.get_connector()`.""" 60 self.connector_id = connector_id 61 """The connector ID.""" 62 63 self.workspace_id = workspace_id 64 """The workspace ID.""" 65 66 self._credentials = credentials 67 self._name = name 68 self._details: AgentConnectorDetails | None = None 69 70 @property 71 def name(self) -> str | None: 72 """The connector name, fetched from the Agents API if not already known.""" 73 if self._name is None: 74 self._name = self.inspect().name 75 return self._name 76 77 def inspect(self, *, force_refresh: bool = False) -> AgentConnectorDetails: 78 """Return connector metadata from the Agents API `inspect` endpoint. 79 80 The result is cached; pass `force_refresh=True` to fetch it again. 81 """ 82 if self._details is None or force_refresh: 83 self._details = AgentConnectorDetails.model_validate( 84 _api_util.inspect_agent_connector( 85 connector_id=self.connector_id, 86 credentials=self._credentials, 87 organization_id=self._credentials.organization_id, 88 ) 89 ) 90 self._name = self._details.name or self._name 91 return self._details 92 93 def execute( # noqa: PLR0913 # Explicit args are the point of this public API. 94 self, 95 entity_type: str, 96 action: AgentAction | str, 97 api_args: dict[str, Any] | None = None, 98 *, 99 select_fields: list[str] | None = None, 100 exclude_fields: list[str] | None = None, 101 page_size: int | None = None, 102 cursor: str | None = None, 103 workspace_id: str | None = None, 104 skip_truncation: bool = True, 105 intent: str | None = None, 106 ) -> AgentExecuteResult: 107 """Execute a single action against one entity type on this connector. 108 109 `entity_type` and `action` are connector-specific, for example `issues` and `list`. 110 Use `inspect()` to see what a connector supports. 111 112 `api_args` holds connector-specific arguments passed through to the connector, for 113 example `{"repository": "airbytehq/PyAirbyte"}`. All other arguments are interpreted 114 by PyAirbyte or by the Agents API itself: 115 116 - `select_fields` and `exclude_fields` prune fields from returned entities. 117 - `page_size` and `cursor` are merged into `api_args` as pagination arguments. Context 118 Store `search` uses `limit` and `cursor`, `sql_select` uses the top-level `cursor`, and 119 direct connector actions use their own pagination arguments in `api_args`. Pass the 120 result cursor according to the action type. 121 - `workspace_id` selects the workspace an action runs against. It defaults to the 122 connector's workspace and is currently sent for `sql_select`, the only action the 123 Agents API scopes by workspace; direct connector actions are scoped by the connector. 124 - `skip_truncation` disables the Agents API's default truncation of large payloads. 125 - `intent` is a free-text description of why the action is being run, which some 126 connectors use to refine results. 127 128 The `download` action is rejected, because it returns a binary stream and PyAirbyte 129 does not yet support streaming responses. 130 """ 131 if action in UNSUPPORTED_ACTIONS: 132 raise PyAirbyteInputError( 133 message=f"The {action!r} action is not supported by PyAirbyte.", 134 guidance=( 135 "This action returns a binary stream instead of JSON, and PyAirbyte does " 136 "not yet support streaming responses." 137 ), 138 context={"entity_type": entity_type, "action": action}, 139 ) 140 141 if action not in {*AgentReadAction, *AgentWriteAction}: 142 action_names = ", ".join( 143 member.value for member in (*AgentReadAction, *AgentWriteAction) 144 ) 145 raise PyAirbyteInputError( 146 message=f"The {action!r} action is not a valid action name for `execute`.", 147 guidance=f"Use one of: {action_names}.", 148 context={"entity_type": entity_type, "action": action}, 149 ) 150 151 action_value = action.value if isinstance(action, Enum) else action 152 params = _build_params(api_args=api_args, page_size=page_size, cursor=cursor) 153 if action_value == AgentReadAction.SQL_SELECT.value: 154 resolved_workspace_id = workspace_id or self.workspace_id 155 if ( 156 resolved_workspace_id is not None 157 and params.get("workspace_id") is None 158 and params.get("workspace_name") is None 159 ): 160 params.pop("workspace_name", None) 161 params["workspace_id"] = resolved_workspace_id 162 request_body: dict[str, Any] = { 163 "entity": entity_type, 164 "action": action_value, 165 "params": params, 166 "skip_truncation": skip_truncation, 167 } 168 if select_fields is not None: 169 request_body["select_fields"] = select_fields 170 if exclude_fields is not None: 171 request_body["exclude_fields"] = exclude_fields 172 if intent is not None: 173 request_body["intent"] = intent 174 175 return AgentExecuteResult.model_validate( 176 _api_util.execute_agent_connector_action( 177 connector_id=self.connector_id, 178 request_body=request_body, 179 credentials=self._credentials, 180 organization_id=self._credentials.organization_id, 181 ) 182 ) 183 184 def list_entities( 185 self, 186 entity_type: str, 187 api_args: dict[str, Any] | None = None, 188 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 189 ) -> AgentExecuteResult: 190 """Run the `list` action, which returns a page of entities of `entity_type`.""" 191 return self.execute(entity_type, "list", api_args, **kwargs) 192 193 def iter_entities( 194 self, 195 entity_type: str, 196 api_args: dict[str, Any] | None = None, 197 *, 198 limit: int | None = None, 199 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `list_entities()`. 200 ) -> Iterator[dict[str, Any]]: 201 """Yield entities of `entity_type`, following the connector's pagination cursor. 202 203 This is the pagination-free way to read entities: each page is fetched lazily as 204 the caller iterates, so no cursor bookkeeping is needed. 205 206 ```python 207 for issue in connector.iter_entities("issues", {"repository": "airbytehq/PyAirbyte"}): 208 print(issue["title"]) 209 ``` 210 211 `limit` caps how many entities are yielded in total, which matters for entity types 212 with no natural end. Pass `page_size` to control how many are fetched per request. 213 214 Iteration stops early if the connector reports another page without advancing its 215 cursor, rather than requesting the same page forever. 216 217 Use `list_entities()` instead when a single page is enough, or when the result's 218 `status`, `warning`, or `execution_metadata` are needed. 219 """ 220 cursor: str | None = kwargs.pop("cursor", None) 221 yield from _api_util.iter_paged_entities( 222 lambda page_cursor: self.list_entities( 223 entity_type, 224 api_args, 225 cursor=page_cursor, 226 **kwargs, 227 ), 228 limit=limit, 229 cursor=cursor, 230 ) 231 232 def search_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 `search` action, which returns matching entities of `entity_type`.""" 239 return self.execute(entity_type, "search", api_args, **kwargs) 240 241 def get_entity( 242 self, 243 entity_type: str, 244 api_args: dict[str, Any] | None = None, 245 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 246 ) -> AgentExecuteResult: 247 """Run the `get` action, which returns a single entity of `entity_type`.""" 248 return self.execute(entity_type, "get", api_args, **kwargs) 249 250 def create_entity( 251 self, 252 entity_type: str, 253 api_args: dict[str, Any] | None = None, 254 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 255 ) -> AgentExecuteResult: 256 """Run the `create` action, which creates an entity of `entity_type`.""" 257 return self.execute(entity_type, "create", api_args, **kwargs) 258 259 def update_entity( 260 self, 261 entity_type: str, 262 api_args: dict[str, Any] | None = None, 263 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 264 ) -> AgentExecuteResult: 265 """Run the `update` action, which updates an entity of `entity_type`.""" 266 return self.execute(entity_type, "update", api_args, **kwargs) 267 268 def delete_entity( 269 self, 270 entity_type: str, 271 api_args: dict[str, Any] | None = None, 272 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 273 ) -> AgentExecuteResult: 274 """Run the `delete` action, which deletes an entity of `entity_type`.""" 275 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"])
51 def __init__( 52 self, 53 connector_id: str, 54 *, 55 credentials: _AirbyteCredentials, 56 name: str | None = None, 57 workspace_id: str | None = None, 58 ) -> None: 59 """Initialize an `AgentConnector`. Prefer `AgentWorkspace.get_connector()`.""" 60 self.connector_id = connector_id 61 """The connector ID.""" 62 63 self.workspace_id = workspace_id 64 """The workspace ID.""" 65 66 self._credentials = credentials 67 self._name = name 68 self._details: AgentConnectorDetails | None = None
Initialize an AgentConnector. Prefer AgentWorkspace.get_connector().
70 @property 71 def name(self) -> str | None: 72 """The connector name, fetched from the Agents API if not already known.""" 73 if self._name is None: 74 self._name = self.inspect().name 75 return self._name
The connector name, fetched from the Agents API if not already known.
77 def inspect(self, *, force_refresh: bool = False) -> AgentConnectorDetails: 78 """Return connector metadata from the Agents API `inspect` endpoint. 79 80 The result is cached; pass `force_refresh=True` to fetch it again. 81 """ 82 if self._details is None or force_refresh: 83 self._details = AgentConnectorDetails.model_validate( 84 _api_util.inspect_agent_connector( 85 connector_id=self.connector_id, 86 credentials=self._credentials, 87 organization_id=self._credentials.organization_id, 88 ) 89 ) 90 self._name = self._details.name or self._name 91 return self._details
Return connector metadata from the Agents API inspect endpoint.
The result is cached; pass force_refresh=True to fetch it again.
93 def execute( # noqa: PLR0913 # Explicit args are the point of this public API. 94 self, 95 entity_type: str, 96 action: AgentAction | str, 97 api_args: dict[str, Any] | None = None, 98 *, 99 select_fields: list[str] | None = None, 100 exclude_fields: list[str] | None = None, 101 page_size: int | None = None, 102 cursor: str | None = None, 103 workspace_id: str | None = None, 104 skip_truncation: bool = True, 105 intent: str | None = None, 106 ) -> AgentExecuteResult: 107 """Execute a single action against one entity type on this connector. 108 109 `entity_type` and `action` are connector-specific, for example `issues` and `list`. 110 Use `inspect()` to see what a connector supports. 111 112 `api_args` holds connector-specific arguments passed through to the connector, for 113 example `{"repository": "airbytehq/PyAirbyte"}`. All other arguments are interpreted 114 by PyAirbyte or by the Agents API itself: 115 116 - `select_fields` and `exclude_fields` prune fields from returned entities. 117 - `page_size` and `cursor` are merged into `api_args` as pagination arguments. Context 118 Store `search` uses `limit` and `cursor`, `sql_select` uses the top-level `cursor`, and 119 direct connector actions use their own pagination arguments in `api_args`. Pass the 120 result cursor according to the action type. 121 - `workspace_id` selects the workspace an action runs against. It defaults to the 122 connector's workspace and is currently sent for `sql_select`, the only action the 123 Agents API scopes by workspace; direct connector actions are scoped by the connector. 124 - `skip_truncation` disables the Agents API's default truncation of large payloads. 125 - `intent` is a free-text description of why the action is being run, which some 126 connectors use to refine results. 127 128 The `download` action is rejected, because it returns a binary stream and PyAirbyte 129 does not yet support streaming responses. 130 """ 131 if action in UNSUPPORTED_ACTIONS: 132 raise PyAirbyteInputError( 133 message=f"The {action!r} action is not supported by PyAirbyte.", 134 guidance=( 135 "This action returns a binary stream instead of JSON, and PyAirbyte does " 136 "not yet support streaming responses." 137 ), 138 context={"entity_type": entity_type, "action": action}, 139 ) 140 141 if action not in {*AgentReadAction, *AgentWriteAction}: 142 action_names = ", ".join( 143 member.value for member in (*AgentReadAction, *AgentWriteAction) 144 ) 145 raise PyAirbyteInputError( 146 message=f"The {action!r} action is not a valid action name for `execute`.", 147 guidance=f"Use one of: {action_names}.", 148 context={"entity_type": entity_type, "action": action}, 149 ) 150 151 action_value = action.value if isinstance(action, Enum) else action 152 params = _build_params(api_args=api_args, page_size=page_size, cursor=cursor) 153 if action_value == AgentReadAction.SQL_SELECT.value: 154 resolved_workspace_id = workspace_id or self.workspace_id 155 if ( 156 resolved_workspace_id is not None 157 and params.get("workspace_id") is None 158 and params.get("workspace_name") is None 159 ): 160 params.pop("workspace_name", None) 161 params["workspace_id"] = resolved_workspace_id 162 request_body: dict[str, Any] = { 163 "entity": entity_type, 164 "action": action_value, 165 "params": params, 166 "skip_truncation": skip_truncation, 167 } 168 if select_fields is not None: 169 request_body["select_fields"] = select_fields 170 if exclude_fields is not None: 171 request_body["exclude_fields"] = exclude_fields 172 if intent is not None: 173 request_body["intent"] = intent 174 175 return AgentExecuteResult.model_validate( 176 _api_util.execute_agent_connector_action( 177 connector_id=self.connector_id, 178 request_body=request_body, 179 credentials=self._credentials, 180 organization_id=self._credentials.organization_id, 181 ) 182 )
Execute a single action against one entity type on this connector.
entity_type and action are connector-specific, for example issues and list.
Use inspect() 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_fieldsandexclude_fieldsprune fields from returned entities.page_sizeandcursorare merged intoapi_argsas pagination arguments. Context Storesearchuseslimitandcursor,sql_selectuses the top-levelcursor, and direct connector actions use their own pagination arguments inapi_args. Pass the result cursor according to the action type.workspace_idselects the workspace an action runs against. It defaults to the connector's workspace and is currently sent forsql_select, the only action the Agents API scopes by workspace; direct connector actions are scoped by the connector.skip_truncationdisables the Agents API's default truncation of large payloads.intentis 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.
184 def list_entities( 185 self, 186 entity_type: str, 187 api_args: dict[str, Any] | None = None, 188 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 189 ) -> AgentExecuteResult: 190 """Run the `list` action, which returns a page of entities of `entity_type`.""" 191 return self.execute(entity_type, "list", api_args, **kwargs)
Run the list action, which returns a page of entities of entity_type.
193 def iter_entities( 194 self, 195 entity_type: str, 196 api_args: dict[str, Any] | None = None, 197 *, 198 limit: int | None = None, 199 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `list_entities()`. 200 ) -> Iterator[dict[str, Any]]: 201 """Yield entities of `entity_type`, following the connector's pagination cursor. 202 203 This is the pagination-free way to read entities: each page is fetched lazily as 204 the caller iterates, so no cursor bookkeeping is needed. 205 206 ```python 207 for issue in connector.iter_entities("issues", {"repository": "airbytehq/PyAirbyte"}): 208 print(issue["title"]) 209 ``` 210 211 `limit` caps how many entities are yielded in total, which matters for entity types 212 with no natural end. Pass `page_size` to control how many are fetched per request. 213 214 Iteration stops early if the connector reports another page without advancing its 215 cursor, rather than requesting the same page forever. 216 217 Use `list_entities()` instead when a single page is enough, or when the result's 218 `status`, `warning`, or `execution_metadata` are needed. 219 """ 220 cursor: str | None = kwargs.pop("cursor", None) 221 yield from _api_util.iter_paged_entities( 222 lambda page_cursor: self.list_entities( 223 entity_type, 224 api_args, 225 cursor=page_cursor, 226 **kwargs, 227 ), 228 limit=limit, 229 cursor=cursor, 230 )
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.
232 def search_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 `search` action, which returns matching entities of `entity_type`.""" 239 return self.execute(entity_type, "search", api_args, **kwargs)
Run the search action, which returns matching entities of entity_type.
241 def get_entity( 242 self, 243 entity_type: str, 244 api_args: dict[str, Any] | None = None, 245 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 246 ) -> AgentExecuteResult: 247 """Run the `get` action, which returns a single entity of `entity_type`.""" 248 return self.execute(entity_type, "get", api_args, **kwargs)
Run the get action, which returns a single entity of entity_type.
250 def create_entity( 251 self, 252 entity_type: str, 253 api_args: dict[str, Any] | None = None, 254 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 255 ) -> AgentExecuteResult: 256 """Run the `create` action, which creates an entity of `entity_type`.""" 257 return self.execute(entity_type, "create", api_args, **kwargs)
Run the create action, which creates an entity of entity_type.
259 def update_entity( 260 self, 261 entity_type: str, 262 api_args: dict[str, Any] | None = None, 263 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 264 ) -> AgentExecuteResult: 265 """Run the `update` action, which updates an entity of `entity_type`.""" 266 return self.execute(entity_type, "update", api_args, **kwargs)
Run the update action, which updates an entity of entity_type.
268 def delete_entity( 269 self, 270 entity_type: str, 271 api_args: dict[str, Any] | None = None, 272 **kwargs: Any, # noqa: ANN401 # Forwarded verbatim to `execute()`. 273 ) -> AgentExecuteResult: 274 """Run the `delete` action, which deletes an entity of `entity_type`.""" 275 return self.execute(entity_type, "delete", api_args, **kwargs)
Run the delete action, which deletes an entity of entity_type.
150class AgentConnectorDetails(BaseModel): 151 """Connector metadata returned by the Agents API `inspect` endpoint.""" 152 153 model_config = ConfigDict(extra="allow", populate_by_name=True) 154 155 connector_id: str 156 """The connector ID.""" 157 158 name: str | None = None 159 """The connector name.""" 160 161 workspace_id: str | None = None 162 """The ID of the workspace the connector belongs to.""" 163 164 organization_id: str | None = None 165 """The ID of the organization the connector belongs to.""" 166 167 source_definition_id: str | None = None 168 """The ID of the underlying Airbyte source definition.""" 169 170 integration_name: str | None = Field(default=None, alias="source_definition_name") 171 """Name of the underlying integration, for example `GitHub` or `Snowflake`.""" 172 173 docs_skill_id: str | None = None 174 """Skill ID to pass to `AgentWorkspace.get_skill(...).read_docs()` (MCP: 175 `read_agent_skill_docs`) for this connector's usage docs.""" 176 177 context_store_readiness: AgentContextStoreReadiness | None = None 178 """Context Store readiness information, when reported.""" 179 180 warnings: list[Any] = Field(default_factory=list) 181 """Warnings reported by the Agents API, for example degraded capabilities.""" 182 183 @property 184 def context_store_entities(self) -> list[str]: 185 """The entity names this connector can cache in the Context Store. 186 187 Note that this lists Context Store-supported entities specifically. The Agents API 188 does not publish an exhaustive list of executable entity and action pairs, so an 189 entity may be executable via `AgentConnector.execute()` without appearing here. 190 """ 191 if self.context_store_readiness is None: 192 return [] 193 return [ 194 entity.entity 195 for entity in self.context_store_readiness.supported_context_store_entities 196 ]
Connector metadata returned by the Agents API inspect endpoint.
Name of the underlying integration, for example GitHub or Snowflake.
Skill ID to pass to AgentWorkspace.get_skill(...).read_docs() (MCP:
read_agent_skill_docs) for this connector's usage docs.
Warnings reported by the Agents API, for example degraded capabilities.
183 @property 184 def context_store_entities(self) -> list[str]: 185 """The entity names this connector can cache in the Context Store. 186 187 Note that this lists Context Store-supported entities specifically. The Agents API 188 does not publish an exhaustive list of executable entity and action pairs, so an 189 entity may be executable via `AgentConnector.execute()` without appearing here. 190 """ 191 if self.context_store_readiness is None: 192 return [] 193 return [ 194 entity.entity 195 for entity in self.context_store_readiness.supported_context_store_entities 196 ]
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.
42class AgentConnectorInfo(BaseModel): 43 """Summary information about a connector, as returned by the Agents API.""" 44 45 model_config = ConfigDict(extra="allow") 46 47 id: str 48 """The connector ID.""" 49 50 name: str | None = None 51 """The connector name, for example `GitHub - <workspace_id>`."""
Summary information about a connector, as returned by the Agents API.
211class AgentConnectorMetadata(BaseModel): 212 """Connector-reported metadata about a single action's result, including pagination.""" 213 214 model_config = ConfigDict(extra="allow") 215 216 has_next_page: bool | None = None 217 """Whether more entities are available after this page, when the connector reports it.""" 218 219 end_cursor: str | None = None 220 """The cursor for the next page, when one is available. Pass it as `cursor` for Context Store 221 `search`, or as the connector's own cursor argument in `api_args` for direct connector 222 actions."""
Connector-reported metadata about a single action's result, including pagination.
54class AgentContextStoreEntity(BaseModel): 55 """An entity that a connector supports caching in the Airbyte Context Store.""" 56 57 model_config = ConfigDict(extra="allow") 58 59 entity: str 60 """The entity name, for example `issues`.""" 61 62 suggested: bool | None = None 63 """Whether Airbyte suggests caching this entity."""
An entity that a connector supports caching in the Airbyte Context Store.
66class AgentContextStoreReadiness(BaseModel): 67 """Context Store readiness information for a connector.""" 68 69 model_config = ConfigDict(extra="allow") 70 71 supported_context_store_entities: list[AgentContextStoreEntity] = Field(default_factory=list) 72 """The entities this connector can cache in the Context Store.""" 73 74 configured_cache_entities: list[dict[str, Any]] = Field(default_factory=list) 75 """The entities currently configured for caching, with their sync status."""
Context Store readiness information for a connector.
225class AgentExecuteResult(BaseModel): 226 """The result of executing a single action against an Airbyte Agents connector.""" 227 228 model_config = ConfigDict(extra="allow") 229 230 status: str 231 """The execution status reported by the Agents API, for example `success`.""" 232 233 result: Any = None 234 """The action's payload. Entity-returning actions put a list of entities here.""" 235 236 connector_metadata: AgentConnectorMetadata = Field(default_factory=AgentConnectorMetadata) 237 """Connector-reported metadata about the result, including pagination cursors.""" 238 239 execution_metadata: AgentExecutionMetadata = Field(default_factory=AgentExecutionMetadata) 240 """Metadata describing how the action was executed.""" 241 242 warning: dict[str, Any] | None = None 243 """A warning reported alongside an otherwise successful result.""" 244 245 @field_validator("connector_metadata", "execution_metadata", mode="before") 246 @classmethod 247 def _none_to_empty(cls, value: object) -> object: 248 return {} if value is None else value 249 250 @property 251 def entities(self) -> list[dict[str, Any]]: 252 """The result as a list of entities. 253 254 Raises `PyAirbyteInputError` if the action did not return a list of entities. Use 255 `result` for actions whose payload is not a list of entities. 256 """ 257 if not isinstance(self.result, list): 258 raise PyAirbyteInputError( 259 message="This action did not return a list of entities.", 260 guidance="Use the `result` attribute to read non-entity result payloads.", 261 context={"result_type": type(self.result).__name__}, 262 ) 263 264 invalid_types = sorted( 265 {type(entity).__name__ for entity in self.result if not isinstance(entity, dict)} 266 ) 267 if invalid_types: 268 raise PyAirbyteInputError( 269 message="This action returned a list that is not a list of entities.", 270 guidance="Use the `result` attribute to read non-entity result payloads.", 271 context={"unexpected_item_types": invalid_types}, 272 ) 273 return self.result 274 275 @property 276 def has_next_page(self) -> bool: 277 """Whether the connector reported more entities after this page.""" 278 return bool(self.connector_metadata.has_next_page) 279 280 @property 281 def end_cursor(self) -> str | None: 282 """The cursor for the next page, or `None` when there is no next page.""" 283 return self.connector_metadata.end_cursor
The result of executing a single action against an Airbyte Agents connector.
The execution status reported by the Agents API, for example success.
A warning reported alongside an otherwise successful result.
250 @property 251 def entities(self) -> list[dict[str, Any]]: 252 """The result as a list of entities. 253 254 Raises `PyAirbyteInputError` if the action did not return a list of entities. Use 255 `result` for actions whose payload is not a list of entities. 256 """ 257 if not isinstance(self.result, list): 258 raise PyAirbyteInputError( 259 message="This action did not return a list of entities.", 260 guidance="Use the `result` attribute to read non-entity result payloads.", 261 context={"result_type": type(self.result).__name__}, 262 ) 263 264 invalid_types = sorted( 265 {type(entity).__name__ for entity in self.result if not isinstance(entity, dict)} 266 ) 267 if invalid_types: 268 raise PyAirbyteInputError( 269 message="This action returned a list that is not a list of entities.", 270 guidance="Use the `result` attribute to read non-entity result payloads.", 271 context={"unexpected_item_types": invalid_types}, 272 ) 273 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.
199class AgentExecutionMetadata(BaseModel): 200 """Metadata describing how an Agents connector action was executed.""" 201 202 model_config = ConfigDict(extra="allow") 203 204 connector_instance_id: str | None = None 205 """The connector instance that served the request.""" 206 207 execution_time_ms: int | None = None 208 """The server-side execution time, in milliseconds."""
Metadata describing how an Agents connector action was executed.
77class AgentOrganization: 78 """An organization on the Airbyte Agents platform. 79 80 ```python 81 from airbyte import agents 82 83 organization = agents.AgentOrganization.from_env() 84 workspace = organization.get_workspace("my-workspace") # by ID or name (case insensitive) 85 ``` 86 """ 87 88 def __init__( 89 self, 90 *, 91 organization_id: str | None = None, 92 client_id: str | SecretString | None = None, 93 client_secret: str | SecretString | None = None, 94 bearer_token: str | SecretString | None = None, 95 public_api_root: str | None = None, 96 config_api_root: str | None = None, 97 ) -> None: 98 """Initialize an `AgentOrganization`. 99 100 Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are 101 not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` / 102 `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset); 103 custom roots require `AIRBYTE_AGENTS_API_URL`. The organization ID is optional: the 104 Agents API infers it when the credentials belong to exactly one organization. 105 """ 106 self._credentials = _AirbyteCredentials.from_auth( 107 organization_id=organization_id, 108 client_id=client_id, 109 client_secret=client_secret, 110 bearer_token=bearer_token, 111 public_api_root=public_api_root, 112 config_api_root=config_api_root, 113 # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env 114 # fallback, since an env bearer token plus explicit client creds is rejected 115 # as mutually exclusive auth. 116 env_vars=not (client_id or client_secret or bearer_token), 117 ) 118 119 self.organization_id: str | None = self._credentials.organization_id 120 """The organization ID, when known.""" 121 122 @classmethod 123 def from_env(cls, organization_id: str | None = None) -> AgentOrganization: 124 """Create an `AgentOrganization` from the `AIRBYTE_CLOUD_*` environment variables.""" 125 return cls(organization_id=organization_id) 126 127 def list_workspaces(self) -> list[AgentWorkspace]: 128 """List the workspaces visible to these credentials in the Agents API.""" 129 return [ 130 self._workspace_from_info(info) 131 for info in ( 132 AgentWorkspaceInfo.model_validate(record) 133 for record in _api_util.list_agent_workspaces( 134 credentials=self._credentials, 135 organization_id=self.organization_id, 136 ) 137 ) 138 ] 139 140 def get_workspace( 141 self, 142 id_or_name: str | None = None, 143 /, 144 *, 145 workspace_id: str | None = None, 146 name: str | None = None, 147 ) -> AgentWorkspace: 148 """Get a workspace in this organization, by ID or by name. 149 150 Pass a single positional value to look the workspace up by either its ID or its 151 name, or name the argument to be explicit. 152 153 Lookup by an explicit `workspace_id` does not call the Agents API. Every other form 154 lists the organization's workspaces and matches on ID first, then on an exact name, 155 ignoring case. 156 """ 157 lookup = _resolve_workspace_lookup( 158 id_or_name, 159 workspace_id=workspace_id, 160 name=name, 161 ) 162 163 if lookup.workspace_id and not lookup.name: 164 return self._workspace_from_info(AgentWorkspaceInfo(id=lookup.workspace_id)) 165 166 workspaces = self.list_workspaces() 167 if lookup.workspace_id: 168 id_matches = [ 169 workspace 170 for workspace in workspaces 171 if workspace.workspace_id == lookup.workspace_id 172 ] 173 if id_matches: 174 return id_matches[0] 175 176 name_lower = (lookup.name or "").lower() 177 matches = [ 178 workspace 179 for workspace in workspaces 180 if workspace.name and workspace.name.lower() == name_lower 181 ] 182 if not matches: 183 raise AirbyteError( 184 message="No workspace found with the given ID or name.", 185 guidance="Use `list_workspaces()` to see the available workspaces.", 186 context={"name": lookup.name}, 187 ) 188 if len(matches) > 1: 189 raise AirbyteError( 190 message="Multiple workspaces matched the given name.", 191 guidance="Pass `workspace_id` instead of `name`.", 192 context={"name": lookup.name, "match_count": len(matches)}, 193 ) 194 return matches[0] 195 196 def as_cloud_organization(self) -> CloudOrganization: 197 """Return this organization as an `airbyte.cloud.CloudOrganization`. 198 199 Every Agents organization is also a Cloud organization, so this conversion needs no 200 API call. It requires a known organization ID, and raises `PyAirbyteInputError` 201 when the ID is unknown. 202 """ 203 if not self.organization_id: 204 raise PyAirbyteInputError( 205 message="Organization ID is required to convert to a `CloudOrganization`.", 206 guidance=( 207 "Provide `organization_id`, or set the `AIRBYTE_CLOUD_ORGANIZATION_ID` " 208 "environment variable." 209 ), 210 ) 211 return CloudOrganization( 212 organization_id=self.organization_id, 213 client_id=self._credentials.client_id, 214 client_secret=self._credentials.client_secret, 215 bearer_token=self._credentials.bearer_token, 216 public_api_root=self._credentials.public_api_root, 217 config_api_root=self._credentials.config_api_root, 218 ) 219 220 @classmethod 221 def from_cloud_organization( 222 cls, 223 cloud_organization: CloudOrganization, 224 ) -> AgentOrganization: 225 """Return a Cloud organization as an `AgentOrganization`. 226 227 Whether the organization can actually execute connector actions depends on its 228 Airbyte Agents subscription, which is only knowable per workspace. Use 229 `AgentWorkspace.from_cloud_workspace()` for an authoritative eligibility check. 230 231 Raises `AirbyteAgentsUnavailableError` when the Cloud organization uses non-public Cloud 232 API roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so 233 the token exchange stays on the same deployment. 234 """ 235 credentials = cloud_organization._credentials # noqa: SLF001 # Same-domain conversion. 236 _api_util.check_public_cloud_api_roots(credentials) 237 return cls( 238 organization_id=cloud_organization.organization_id, 239 client_id=credentials.client_id, 240 client_secret=credentials.client_secret, 241 bearer_token=credentials.bearer_token, 242 public_api_root=credentials.public_api_root, 243 config_api_root=credentials.config_api_root, 244 ) 245 246 def _workspace_from_info(self, info: AgentWorkspaceInfo) -> AgentWorkspace: 247 """Build an `AgentWorkspace` from workspace info, reusing these credentials.""" 248 return AgentWorkspace( 249 workspace_id=info.id, 250 organization_id=info.organization_id or self.organization_id, 251 name=info.name, 252 client_id=self._credentials.client_id, 253 client_secret=self._credentials.client_secret, 254 bearer_token=self._credentials.bearer_token, 255 public_api_root=self._credentials.public_api_root, 256 config_api_root=self._credentials.config_api_root, 257 )
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)
88 def __init__( 89 self, 90 *, 91 organization_id: str | None = None, 92 client_id: str | SecretString | None = None, 93 client_secret: str | SecretString | None = None, 94 bearer_token: str | SecretString | None = None, 95 public_api_root: str | None = None, 96 config_api_root: str | None = None, 97 ) -> None: 98 """Initialize an `AgentOrganization`. 99 100 Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are 101 not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` / 102 `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset); 103 custom roots require `AIRBYTE_AGENTS_API_URL`. The organization ID is optional: the 104 Agents API infers it when the credentials belong to exactly one organization. 105 """ 106 self._credentials = _AirbyteCredentials.from_auth( 107 organization_id=organization_id, 108 client_id=client_id, 109 client_secret=client_secret, 110 bearer_token=bearer_token, 111 public_api_root=public_api_root, 112 config_api_root=config_api_root, 113 # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env 114 # fallback, since an env bearer token plus explicit client creds is rejected 115 # as mutually exclusive auth. 116 env_vars=not (client_id or client_secret or bearer_token), 117 ) 118 119 self.organization_id: str | None = self._credentials.organization_id 120 """The organization ID, when known."""
Initialize an AgentOrganization.
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. The organization ID is optional: the
Agents API infers it when the credentials belong to exactly one organization.
122 @classmethod 123 def from_env(cls, organization_id: str | None = None) -> AgentOrganization: 124 """Create an `AgentOrganization` from the `AIRBYTE_CLOUD_*` environment variables.""" 125 return cls(organization_id=organization_id)
Create an AgentOrganization from the AIRBYTE_CLOUD_* environment variables.
127 def list_workspaces(self) -> list[AgentWorkspace]: 128 """List the workspaces visible to these credentials in the Agents API.""" 129 return [ 130 self._workspace_from_info(info) 131 for info in ( 132 AgentWorkspaceInfo.model_validate(record) 133 for record in _api_util.list_agent_workspaces( 134 credentials=self._credentials, 135 organization_id=self.organization_id, 136 ) 137 ) 138 ]
List the workspaces visible to these credentials in the Agents API.
140 def get_workspace( 141 self, 142 id_or_name: str | None = None, 143 /, 144 *, 145 workspace_id: str | None = None, 146 name: str | None = None, 147 ) -> AgentWorkspace: 148 """Get a workspace in this organization, by ID or by name. 149 150 Pass a single positional value to look the workspace up by either its ID or its 151 name, or name the argument to be explicit. 152 153 Lookup by an explicit `workspace_id` does not call the Agents API. Every other form 154 lists the organization's workspaces and matches on ID first, then on an exact name, 155 ignoring case. 156 """ 157 lookup = _resolve_workspace_lookup( 158 id_or_name, 159 workspace_id=workspace_id, 160 name=name, 161 ) 162 163 if lookup.workspace_id and not lookup.name: 164 return self._workspace_from_info(AgentWorkspaceInfo(id=lookup.workspace_id)) 165 166 workspaces = self.list_workspaces() 167 if lookup.workspace_id: 168 id_matches = [ 169 workspace 170 for workspace in workspaces 171 if workspace.workspace_id == lookup.workspace_id 172 ] 173 if id_matches: 174 return id_matches[0] 175 176 name_lower = (lookup.name or "").lower() 177 matches = [ 178 workspace 179 for workspace in workspaces 180 if workspace.name and workspace.name.lower() == name_lower 181 ] 182 if not matches: 183 raise AirbyteError( 184 message="No workspace found with the given ID or name.", 185 guidance="Use `list_workspaces()` to see the available workspaces.", 186 context={"name": lookup.name}, 187 ) 188 if len(matches) > 1: 189 raise AirbyteError( 190 message="Multiple workspaces matched the given name.", 191 guidance="Pass `workspace_id` instead of `name`.", 192 context={"name": lookup.name, "match_count": len(matches)}, 193 ) 194 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.
196 def as_cloud_organization(self) -> CloudOrganization: 197 """Return this organization as an `airbyte.cloud.CloudOrganization`. 198 199 Every Agents organization is also a Cloud organization, so this conversion needs no 200 API call. It requires a known organization ID, and raises `PyAirbyteInputError` 201 when the ID is unknown. 202 """ 203 if not self.organization_id: 204 raise PyAirbyteInputError( 205 message="Organization ID is required to convert to a `CloudOrganization`.", 206 guidance=( 207 "Provide `organization_id`, or set the `AIRBYTE_CLOUD_ORGANIZATION_ID` " 208 "environment variable." 209 ), 210 ) 211 return CloudOrganization( 212 organization_id=self.organization_id, 213 client_id=self._credentials.client_id, 214 client_secret=self._credentials.client_secret, 215 bearer_token=self._credentials.bearer_token, 216 public_api_root=self._credentials.public_api_root, 217 config_api_root=self._credentials.config_api_root, 218 )
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.
220 @classmethod 221 def from_cloud_organization( 222 cls, 223 cloud_organization: CloudOrganization, 224 ) -> AgentOrganization: 225 """Return a Cloud organization as an `AgentOrganization`. 226 227 Whether the organization can actually execute connector actions depends on its 228 Airbyte Agents subscription, which is only knowable per workspace. Use 229 `AgentWorkspace.from_cloud_workspace()` for an authoritative eligibility check. 230 231 Raises `AirbyteAgentsUnavailableError` when the Cloud organization uses non-public Cloud 232 API roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so 233 the token exchange stays on the same deployment. 234 """ 235 credentials = cloud_organization._credentials # noqa: SLF001 # Same-domain conversion. 236 _api_util.check_public_cloud_api_roots(credentials) 237 return cls( 238 organization_id=cloud_organization.organization_id, 239 client_id=credentials.client_id, 240 client_secret=credentials.client_secret, 241 bearer_token=credentials.bearer_token, 242 public_api_root=credentials.public_api_root, 243 config_api_root=credentials.config_api_root, 244 )
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 AirbyteAgentsUnavailableError when the Cloud organization 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.
27class AgentSkill: 28 """A skill on the Airbyte Agents platform. 29 30 Get one from `AgentWorkspace.get_skill()` or `AgentWorkspace.list_skills()` rather than 31 constructing it directly. 32 """ 33 34 def __init__( 35 self, 36 skill_id: str, 37 *, 38 credentials: _AirbyteCredentials, 39 workspace_id: str | None = None, 40 info: AgentSkillInfo | None = None, 41 ) -> None: 42 """Initialize an `AgentSkill`. Prefer `AgentWorkspace.get_skill()`.""" 43 self.skill_id = skill_id 44 """The skill ID.""" 45 46 self._credentials = credentials 47 self._workspace_id = workspace_id 48 self._info = info 49 50 @property 51 def info(self) -> AgentSkillInfo: 52 """The skill's metadata, fetched from the Agents API if not already known.""" 53 if self._info is None: 54 self._info = self.read_docs().metadata 55 return self._info 56 57 @property 58 def title(self) -> str | None: 59 """The human-readable skill title.""" 60 return self.info.title 61 62 @property 63 def kind(self) -> str | None: 64 """The skill category, for example `static` or `connector_source`.""" 65 return self.info.kind 66 67 def read_docs(self, *, section: str | None = None) -> AgentSkillDocs: 68 """Read this skill's docs, optionally scoped to a single section. 69 70 Omit `section` for metadata, guidance, and the outline of available sections, or 71 pass an exact section `id` from the outline to read that section. 72 """ 73 docs = AgentSkillDocs.model_validate( 74 _api_util.read_agent_skill_docs( 75 skill_id=self.skill_id, 76 credentials=self._credentials, 77 organization_id=self._credentials.organization_id, 78 workspace_id=self._workspace_id, 79 section=section, 80 ) 81 ) 82 if self._info is None: 83 self._info = docs.metadata 84 return docs
A skill on the Airbyte Agents platform.
Get one from AgentWorkspace.get_skill() or AgentWorkspace.list_skills() rather than
constructing it directly.
34 def __init__( 35 self, 36 skill_id: str, 37 *, 38 credentials: _AirbyteCredentials, 39 workspace_id: str | None = None, 40 info: AgentSkillInfo | None = None, 41 ) -> None: 42 """Initialize an `AgentSkill`. Prefer `AgentWorkspace.get_skill()`.""" 43 self.skill_id = skill_id 44 """The skill ID.""" 45 46 self._credentials = credentials 47 self._workspace_id = workspace_id 48 self._info = info
Initialize an AgentSkill. Prefer AgentWorkspace.get_skill().
50 @property 51 def info(self) -> AgentSkillInfo: 52 """The skill's metadata, fetched from the Agents API if not already known.""" 53 if self._info is None: 54 self._info = self.read_docs().metadata 55 return self._info
The skill's metadata, fetched from the Agents API if not already known.
57 @property 58 def title(self) -> str | None: 59 """The human-readable skill title.""" 60 return self.info.title
The human-readable skill title.
62 @property 63 def kind(self) -> str | None: 64 """The skill category, for example `static` or `connector_source`.""" 65 return self.info.kind
The skill category, for example static or connector_source.
67 def read_docs(self, *, section: str | None = None) -> AgentSkillDocs: 68 """Read this skill's docs, optionally scoped to a single section. 69 70 Omit `section` for metadata, guidance, and the outline of available sections, or 71 pass an exact section `id` from the outline to read that section. 72 """ 73 docs = AgentSkillDocs.model_validate( 74 _api_util.read_agent_skill_docs( 75 skill_id=self.skill_id, 76 credentials=self._credentials, 77 organization_id=self._credentials.organization_id, 78 workspace_id=self._workspace_id, 79 section=section, 80 ) 81 ) 82 if self._info is None: 83 self._info = docs.metadata 84 return docs
Read this 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.
132class AgentSkillDocs(BaseModel): 133 """Documentation for a single skill, as returned by the Agents API.""" 134 135 model_config = ConfigDict(extra="allow") 136 137 metadata: AgentSkillInfo 138 """Metadata for the requested skill.""" 139 140 outline: list[AgentSkillSection] = Field(default_factory=list) 141 """The sections available for this skill.""" 142 143 section_id: str | None = None 144 """The requested section ID, or `None` for the default docs response.""" 145 146 content: list[dict[str, Any]] = Field(default_factory=list) 147 """Rendered docs content blocks, such as headings, paragraphs, and code blocks."""
Documentation for a single skill, as returned by the Agents API.
78class AgentSkillInfo(BaseModel): 79 """Summary information about a skill, as returned by the Agents API.""" 80 81 model_config = ConfigDict(extra="allow") 82 83 id: str 84 """The skill ID. Pass it to `read_skill_docs` to read this skill's docs.""" 85 86 kind: str | None = None 87 """The skill category, for example `static` or `connector_source`.""" 88 89 title: str | None = None 90 """The human-readable skill title.""" 91 92 summary: str | None = None 93 """A short summary of what the skill documents.""" 94 95 tags: list[str] = Field(default_factory=list) 96 """Search and categorization tags for the skill.""" 97 98 warnings: list[Any] = Field(default_factory=list) 99 """Non-fatal issues reported while building or reading the skill's docs."""
Summary information about a skill, as returned by the Agents API.
102class AgentSkillList(BaseModel): 103 """A page of skills, as returned by the Agents API.""" 104 105 model_config = ConfigDict(extra="allow") 106 107 data: list[AgentSkillInfo] 108 """The skills on this page.""" 109 110 next_cursor: str | None = None 111 """The cursor to pass as `cursor` to fetch the next page, when one is available."""
A page of skills, as returned by the Agents API.
114class AgentSkillSection(BaseModel): 115 """A section of a skill's docs, as listed in the docs outline.""" 116 117 model_config = ConfigDict(extra="allow") 118 119 id: str 120 """The section ID. Pass it as `section` to read this section.""" 121 122 title: str | None = None 123 """The human-readable section title.""" 124 125 summary: str | None = None 126 """A short summary of the section content.""" 127 128 available: bool = True 129 """Whether this section can currently be read."""
A section of a skill's docs, as listed in the docs outline.
35class AgentWorkspace: 36 """A workspace on the Airbyte Agents platform. 37 38 Airbyte Cloud credentials authenticate against the Agents API, so this class reads the 39 same `AIRBYTE_CLOUD_*` environment variables as `airbyte.cloud.CloudWorkspace`. 40 41 ```python 42 from airbyte import agents 43 44 workspace = agents.AgentWorkspace.from_env() 45 for connector in workspace.list_connectors(): 46 print(connector.name) 47 ``` 48 """ 49 50 def __init__( 51 self, 52 *, 53 workspace_id: str | None = None, 54 organization_id: str | None = None, 55 name: str | None = None, 56 client_id: str | SecretString | None = None, 57 client_secret: str | SecretString | None = None, 58 bearer_token: str | SecretString | None = None, 59 public_api_root: str | None = None, 60 config_api_root: str | None = None, 61 ) -> None: 62 """Initialize an `AgentWorkspace`. 63 64 Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are 65 not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` / 66 `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset); 67 custom roots require `AIRBYTE_AGENTS_API_URL`. 68 """ 69 credentials = _AirbyteCredentials.from_auth( 70 workspace_id=workspace_id, 71 organization_id=organization_id, 72 client_id=client_id, 73 client_secret=client_secret, 74 bearer_token=bearer_token, 75 public_api_root=public_api_root, 76 config_api_root=config_api_root, 77 # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env 78 # fallback, since an env bearer token plus explicit client creds is rejected 79 # as mutually exclusive auth. 80 env_vars=not (client_id or client_secret or bearer_token), 81 ) 82 if not credentials.workspace_id: 83 raise PyAirbyteInputError( 84 message="Workspace ID is required.", 85 guidance=( 86 "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` " 87 "environment variable." 88 ), 89 ) 90 91 self._credentials = credentials 92 93 self.workspace_id: str = credentials.workspace_id 94 """The workspace ID.""" 95 96 self.organization_id: str | None = credentials.organization_id 97 """The organization ID, sent to the Agents API when it is known.""" 98 99 self.name: str | None = name 100 """The workspace name, when known. Use `get_info()` to fetch it from the API.""" 101 102 @classmethod 103 def from_env( 104 cls, 105 workspace_id: str | None = None, 106 *, 107 organization_id: str | None = None, 108 ) -> AgentWorkspace: 109 """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables. 110 111 The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the 112 `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with 113 `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`. 114 """ 115 return cls(workspace_id=workspace_id, organization_id=organization_id) 116 117 def get_info(self) -> AgentWorkspaceInfo: 118 """Fetch this workspace from the Agents API. 119 120 A successful call is authoritative proof that the workspace is reachable through 121 the Agents API with these credentials. 122 """ 123 return AgentWorkspaceInfo.model_validate( 124 _api_util.get_agent_workspace( 125 workspace_id=self.workspace_id, 126 credentials=self._credentials, 127 organization_id=self.organization_id, 128 ) 129 ) 130 131 def list_connectors(self) -> list[AgentConnector]: 132 """List the connectors configured in this workspace.""" 133 return [ 134 AgentConnector( 135 connector_id=info.id, 136 name=info.name, 137 credentials=self._credentials, 138 workspace_id=self.workspace_id, 139 ) 140 for info in ( 141 AgentConnectorInfo.model_validate(record) 142 for record in _api_util.list_agent_connectors( 143 workspace_id=self.workspace_id, 144 credentials=self._credentials, 145 organization_id=self.organization_id, 146 ) 147 ) 148 ] 149 150 def list_skills(self) -> list[AgentSkill]: 151 """List all skills available to this workspace, following pagination.""" 152 return [ 153 AgentSkill( 154 skill_id=info.id, 155 credentials=self._credentials, 156 workspace_id=self.workspace_id, 157 info=info, 158 ) 159 for info in _skills.iter_skills( 160 credentials=self._credentials, 161 workspace_id=self.workspace_id, 162 ) 163 ] 164 165 def get_skill(self, skill_id: str) -> AgentSkill: 166 """Get a skill by ID, without calling the Agents API.""" 167 return AgentSkill( 168 skill_id, 169 credentials=self._credentials, 170 workspace_id=self.workspace_id, 171 ) 172 173 def read_skill_docs( 174 self, 175 skill_id: str, 176 *, 177 section: str | None = None, 178 ) -> AgentSkillDocs: 179 """Read a skill's docs, optionally scoped to a single section. 180 181 Omit `section` for metadata, guidance, and the outline of available sections, or 182 pass an exact section `id` from the outline to read that section. Connector usage 183 docs use the `docs_skill_id` reported by `AgentConnector.inspect()`. 184 """ 185 return self.get_skill(skill_id).read_docs(section=section) 186 187 def get_connector( 188 self, 189 id_or_name: str | None = None, 190 /, 191 *, 192 id: str | None = None, # noqa: A002 # Shadows `id` deliberately, as a short alias. 193 connector_id: str | None = None, 194 name: str | None = None, 195 ) -> AgentConnector: 196 """Get a connector in this workspace, by ID or by name. 197 198 Pass a single positional value to look the connector up by either its ID or its 199 name, or name the argument to be explicit: `id` and `connector_id` are synonyms, 200 so pass whichever reads better. 201 202 Lookup by an explicit ID does not call the Agents API. Every other form lists the 203 workspace's connectors and matches on ID first, then on an exact name, then on a 204 unique substring, so `name="GitHub"` finds a connector named 205 `GitHub - <workspace_id>`. Name matching is case-insensitive. 206 """ 207 lookup = _resolve_connector_lookup( 208 id_or_name, 209 id=id, 210 connector_id=connector_id, 211 name=name, 212 ) 213 214 if lookup.connector_id and not lookup.name: 215 return AgentConnector( 216 connector_id=lookup.connector_id, 217 credentials=self._credentials, 218 workspace_id=self.workspace_id, 219 ) 220 221 connectors = self.list_connectors() 222 if lookup.connector_id: 223 id_matches = [ 224 connector 225 for connector in connectors 226 if connector.connector_id == lookup.connector_id 227 ] 228 if id_matches: 229 return id_matches[0] 230 231 name_lower = (lookup.name or "").lower() 232 matches = [ 233 connector 234 for connector in connectors 235 if connector.name and connector.name.lower() == name_lower 236 ] or [ 237 connector 238 for connector in connectors 239 if connector.name and name_lower in connector.name.lower() 240 ] 241 if not matches: 242 raise AirbyteError( 243 message="No connector found with the given ID or name.", 244 guidance="Use `list_connectors()` to see the available connectors.", 245 context={"lookup": lookup.name, "workspace_id": self.workspace_id}, 246 ) 247 if len(matches) > 1: 248 raise AirbyteError( 249 message="Multiple connectors matched the given name.", 250 guidance="Pass `connector_id`, or a name that matches only one connector.", 251 context={ 252 "name": lookup.name, 253 "matched_names": [connector.name for connector in matches], 254 }, 255 ) 256 return matches[0] 257 258 def as_cloud_workspace(self) -> CloudWorkspace: 259 """Return this workspace as an `airbyte.cloud.CloudWorkspace`. 260 261 Every Agents workspace is also a Cloud workspace, so this conversion always 262 succeeds without calling either API. 263 """ 264 return CloudWorkspace( 265 workspace_id=self.workspace_id, 266 client_id=self._credentials.client_id, 267 client_secret=self._credentials.client_secret, 268 bearer_token=self._credentials.bearer_token, 269 api_root=self._credentials.public_api_root, 270 config_api_root=self._credentials.config_api_root, 271 ) 272 273 @classmethod 274 def from_cloud_workspace( 275 cls, 276 cloud_workspace: CloudWorkspace, 277 *, 278 organization_id: str | None = None, 279 verify: bool = True, 280 ) -> AgentWorkspace: 281 """Return a Cloud workspace as an `AgentWorkspace`. 282 283 Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is 284 reachable through the Agents API: the organization needs an Airbyte Agents 285 subscription. By default this is verified by fetching the workspace from the Agents 286 API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to 287 skip that call. 288 289 Raises `AirbyteAgentsUnavailableError` when the Cloud workspace uses non-public Cloud API 290 roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so the 291 token exchange stays on the same deployment. 292 """ 293 _api_util.check_public_cloud_api_roots( 294 cloud_workspace._credentials, # noqa: SLF001 # Same-domain conversion. 295 ) 296 workspace = cls( 297 workspace_id=cloud_workspace.workspace_id, 298 organization_id=organization_id, 299 client_id=cloud_workspace.client_id, 300 client_secret=cloud_workspace.client_secret, 301 bearer_token=cloud_workspace.bearer_token, 302 public_api_root=cloud_workspace._credentials.public_api_root, # noqa: SLF001 303 config_api_root=cloud_workspace._credentials.config_api_root, # noqa: SLF001 304 ) 305 if verify: 306 workspace.get_info() 307 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)
50 def __init__( 51 self, 52 *, 53 workspace_id: str | None = None, 54 organization_id: str | None = None, 55 name: str | None = None, 56 client_id: str | SecretString | None = None, 57 client_secret: str | SecretString | None = None, 58 bearer_token: str | SecretString | None = None, 59 public_api_root: str | None = None, 60 config_api_root: str | None = None, 61 ) -> None: 62 """Initialize an `AgentWorkspace`. 63 64 Credentials fall back to the `AIRBYTE_CLOUD_*` environment variables when they are 65 not passed explicitly. API roots default to the `AIRBYTE_CLOUD_API_URL` / 66 `AIRBYTE_CLOUD_CONFIG_API_URL` environment variables (public Airbyte Cloud when unset); 67 custom roots require `AIRBYTE_AGENTS_API_URL`. 68 """ 69 credentials = _AirbyteCredentials.from_auth( 70 workspace_id=workspace_id, 71 organization_id=organization_id, 72 client_id=client_id, 73 client_secret=client_secret, 74 bearer_token=bearer_token, 75 public_api_root=public_api_root, 76 config_api_root=config_api_root, 77 # Mirrors `CloudWorkspace.__init__`: any explicit credential disables env 78 # fallback, since an env bearer token plus explicit client creds is rejected 79 # as mutually exclusive auth. 80 env_vars=not (client_id or client_secret or bearer_token), 81 ) 82 if not credentials.workspace_id: 83 raise PyAirbyteInputError( 84 message="Workspace ID is required.", 85 guidance=( 86 "Provide `workspace_id`, or set the `AIRBYTE_CLOUD_WORKSPACE_ID` " 87 "environment variable." 88 ), 89 ) 90 91 self._credentials = credentials 92 93 self.workspace_id: str = credentials.workspace_id 94 """The workspace ID.""" 95 96 self.organization_id: str | None = credentials.organization_id 97 """The organization ID, sent to the Agents API when it is known.""" 98 99 self.name: str | None = name 100 """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.
102 @classmethod 103 def from_env( 104 cls, 105 workspace_id: str | None = None, 106 *, 107 organization_id: str | None = None, 108 ) -> AgentWorkspace: 109 """Create an `AgentWorkspace` from the `AIRBYTE_CLOUD_*` environment variables. 110 111 The variables used are `AIRBYTE_CLOUD_BEARER_TOKEN` or the 112 `AIRBYTE_CLOUD_CLIENT_ID` and `AIRBYTE_CLOUD_CLIENT_SECRET` pair, along with 113 `AIRBYTE_CLOUD_WORKSPACE_ID` and `AIRBYTE_CLOUD_ORGANIZATION_ID`. 114 """ 115 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.
117 def get_info(self) -> AgentWorkspaceInfo: 118 """Fetch this workspace from the Agents API. 119 120 A successful call is authoritative proof that the workspace is reachable through 121 the Agents API with these credentials. 122 """ 123 return AgentWorkspaceInfo.model_validate( 124 _api_util.get_agent_workspace( 125 workspace_id=self.workspace_id, 126 credentials=self._credentials, 127 organization_id=self.organization_id, 128 ) 129 )
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.
131 def list_connectors(self) -> list[AgentConnector]: 132 """List the connectors configured in this workspace.""" 133 return [ 134 AgentConnector( 135 connector_id=info.id, 136 name=info.name, 137 credentials=self._credentials, 138 workspace_id=self.workspace_id, 139 ) 140 for info in ( 141 AgentConnectorInfo.model_validate(record) 142 for record in _api_util.list_agent_connectors( 143 workspace_id=self.workspace_id, 144 credentials=self._credentials, 145 organization_id=self.organization_id, 146 ) 147 ) 148 ]
List the connectors configured in this workspace.
150 def list_skills(self) -> list[AgentSkill]: 151 """List all skills available to this workspace, following pagination.""" 152 return [ 153 AgentSkill( 154 skill_id=info.id, 155 credentials=self._credentials, 156 workspace_id=self.workspace_id, 157 info=info, 158 ) 159 for info in _skills.iter_skills( 160 credentials=self._credentials, 161 workspace_id=self.workspace_id, 162 ) 163 ]
List all skills available to this workspace, following pagination.
165 def get_skill(self, skill_id: str) -> AgentSkill: 166 """Get a skill by ID, without calling the Agents API.""" 167 return AgentSkill( 168 skill_id, 169 credentials=self._credentials, 170 workspace_id=self.workspace_id, 171 )
Get a skill by ID, without calling the Agents API.
173 def read_skill_docs( 174 self, 175 skill_id: str, 176 *, 177 section: str | None = None, 178 ) -> AgentSkillDocs: 179 """Read a skill's docs, optionally scoped to a single section. 180 181 Omit `section` for metadata, guidance, and the outline of available sections, or 182 pass an exact section `id` from the outline to read that section. Connector usage 183 docs use the `docs_skill_id` reported by `AgentConnector.inspect()`. 184 """ 185 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().
187 def get_connector( 188 self, 189 id_or_name: str | None = None, 190 /, 191 *, 192 id: str | None = None, # noqa: A002 # Shadows `id` deliberately, as a short alias. 193 connector_id: str | None = None, 194 name: str | None = None, 195 ) -> AgentConnector: 196 """Get a connector in this workspace, by ID or by name. 197 198 Pass a single positional value to look the connector up by either its ID or its 199 name, or name the argument to be explicit: `id` and `connector_id` are synonyms, 200 so pass whichever reads better. 201 202 Lookup by an explicit ID does not call the Agents API. Every other form lists the 203 workspace's connectors and matches on ID first, then on an exact name, then on a 204 unique substring, so `name="GitHub"` finds a connector named 205 `GitHub - <workspace_id>`. Name matching is case-insensitive. 206 """ 207 lookup = _resolve_connector_lookup( 208 id_or_name, 209 id=id, 210 connector_id=connector_id, 211 name=name, 212 ) 213 214 if lookup.connector_id and not lookup.name: 215 return AgentConnector( 216 connector_id=lookup.connector_id, 217 credentials=self._credentials, 218 workspace_id=self.workspace_id, 219 ) 220 221 connectors = self.list_connectors() 222 if lookup.connector_id: 223 id_matches = [ 224 connector 225 for connector in connectors 226 if connector.connector_id == lookup.connector_id 227 ] 228 if id_matches: 229 return id_matches[0] 230 231 name_lower = (lookup.name or "").lower() 232 matches = [ 233 connector 234 for connector in connectors 235 if connector.name and connector.name.lower() == name_lower 236 ] or [ 237 connector 238 for connector in connectors 239 if connector.name and name_lower in connector.name.lower() 240 ] 241 if not matches: 242 raise AirbyteError( 243 message="No connector found with the given ID or name.", 244 guidance="Use `list_connectors()` to see the available connectors.", 245 context={"lookup": lookup.name, "workspace_id": self.workspace_id}, 246 ) 247 if len(matches) > 1: 248 raise AirbyteError( 249 message="Multiple connectors matched the given name.", 250 guidance="Pass `connector_id`, or a name that matches only one connector.", 251 context={ 252 "name": lookup.name, 253 "matched_names": [connector.name for connector in matches], 254 }, 255 ) 256 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.
258 def as_cloud_workspace(self) -> CloudWorkspace: 259 """Return this workspace as an `airbyte.cloud.CloudWorkspace`. 260 261 Every Agents workspace is also a Cloud workspace, so this conversion always 262 succeeds without calling either API. 263 """ 264 return CloudWorkspace( 265 workspace_id=self.workspace_id, 266 client_id=self._credentials.client_id, 267 client_secret=self._credentials.client_secret, 268 bearer_token=self._credentials.bearer_token, 269 api_root=self._credentials.public_api_root, 270 config_api_root=self._credentials.config_api_root, 271 )
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.
273 @classmethod 274 def from_cloud_workspace( 275 cls, 276 cloud_workspace: CloudWorkspace, 277 *, 278 organization_id: str | None = None, 279 verify: bool = True, 280 ) -> AgentWorkspace: 281 """Return a Cloud workspace as an `AgentWorkspace`. 282 283 Cloud workspace IDs are also Agents workspace IDs, but not every Cloud workspace is 284 reachable through the Agents API: the organization needs an Airbyte Agents 285 subscription. By default this is verified by fetching the workspace from the Agents 286 API, which raises `AirbyteError` when it is not eligible. Pass `verify=False` to 287 skip that call. 288 289 Raises `AirbyteAgentsUnavailableError` when the Cloud workspace uses non-public Cloud API 290 roots unless `AIRBYTE_AGENTS_API_URL` is set; the Cloud API roots are carried over so the 291 token exchange stays on the same deployment. 292 """ 293 _api_util.check_public_cloud_api_roots( 294 cloud_workspace._credentials, # noqa: SLF001 # Same-domain conversion. 295 ) 296 workspace = cls( 297 workspace_id=cloud_workspace.workspace_id, 298 organization_id=organization_id, 299 client_id=cloud_workspace.client_id, 300 client_secret=cloud_workspace.client_secret, 301 bearer_token=cloud_workspace.bearer_token, 302 public_api_root=cloud_workspace._credentials.public_api_root, # noqa: SLF001 303 config_api_root=cloud_workspace._credentials.config_api_root, # noqa: SLF001 304 ) 305 if verify: 306 workspace.get_info() 307 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.
24class AgentWorkspaceInfo(BaseModel): 25 """Summary information about a workspace, as returned by the Agents API.""" 26 27 model_config = ConfigDict(extra="allow") 28 29 id: str 30 """The workspace ID.""" 31 32 name: str | None = None 33 """The workspace name.""" 34 35 organization_id: str | None = None 36 """The ID of the organization the workspace belongs to.""" 37 38 status: str | None = None 39 """The workspace status, for example `active`."""
Summary information about a workspace, as returned by the Agents API.