airbyte-agent-greenhouse 0.17.37__tar.gz → 0.17.40__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/CHANGELOG.md +15 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/PKG-INFO +11 -8
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/README.md +2 -2
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/__init__.py +38 -1
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/cloud_utils/client.py +26 -26
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/executor/hosted_executor.py +10 -11
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/executor/local_executor.py +69 -9
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/connector.py +22 -33
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/pyproject.toml +10 -7
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/.gitignore +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/REFERENCE.md +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/auth_strategies.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/auth_template.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/cloud_utils/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/connector_model_loader.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/constants.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/exceptions.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/executor/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/executor/models.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/extensions.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/adapters/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/adapters/httpx_adapter.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/config.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/exceptions.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/protocols.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http/response.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/http_client.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/introspection.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/logging/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/logging/logger.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/logging/types.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/observability/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/observability/config.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/observability/models.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/observability/redactor.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/observability/session.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/performance/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/performance/instrumentation.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/performance/metrics.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/base.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/components.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/extensions.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/operations.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/schema/security.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/secrets.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/telemetry/__init__.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/telemetry/config.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/telemetry/events.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/telemetry/tracker.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/types.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/utils.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/_vendored/connector_sdk/validation.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/connector.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/connector_model.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/models.py +0 -0
- {airbyte_agent_greenhouse-0.17.37 → airbyte_agent_greenhouse-0.17.40}/airbyte_agent_greenhouse/types.py +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Greenhouse changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.40] - 2026-01-15
|
|
4
|
+
- Updated connector definition (YAML version 0.1.2)
|
|
5
|
+
- Source commit: b7138b41
|
|
6
|
+
- SDK version: 0.1.0
|
|
7
|
+
|
|
8
|
+
## [0.17.39] - 2026-01-15
|
|
9
|
+
- Updated connector definition (YAML version 0.1.2)
|
|
10
|
+
- Source commit: 10173eb1
|
|
11
|
+
- SDK version: 0.1.0
|
|
12
|
+
|
|
13
|
+
## [0.17.38] - 2026-01-15
|
|
14
|
+
- Updated connector definition (YAML version 0.1.2)
|
|
15
|
+
- Source commit: a23d9e7a
|
|
16
|
+
- SDK version: 0.1.0
|
|
17
|
+
|
|
3
18
|
## [0.17.37] - 2026-01-14
|
|
4
19
|
- Updated connector definition (YAML version 0.1.2)
|
|
5
20
|
- Source commit: 7ef09816
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-greenhouse
|
|
3
|
-
Version: 0.17.
|
|
3
|
+
Version: 0.17.40
|
|
4
4
|
Summary: Airbyte Greenhouse Connector for AI platforms
|
|
5
|
-
Project-URL: Homepage, https://github.com/airbytehq/airbyte-
|
|
6
|
-
Project-URL: Documentation, https://
|
|
7
|
-
Project-URL: Repository, https://github.com/airbytehq/airbyte-
|
|
8
|
-
Project-URL: Issues, https://github.com/airbytehq/airbyte-
|
|
5
|
+
Project-URL: Homepage, https://github.com/airbytehq/airbyte-agent-connectors
|
|
6
|
+
Project-URL: Documentation, https://docs.airbyte.com/ai-agents/
|
|
7
|
+
Project-URL: Repository, https://github.com/airbytehq/airbyte-agent-connectors
|
|
8
|
+
Project-URL: Issues, https://github.com/airbytehq/airbyte-agent-connectors/issues
|
|
9
9
|
Author-email: Airbyte <contact@airbyte.io>
|
|
10
10
|
License: Elastic-2.0
|
|
11
|
-
Keywords: airbyte,api,connector,greenhouse
|
|
11
|
+
Keywords: agent,ai,airbyte,api,connector,data-integration,greenhouse,llm,mcp
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: Other/Proprietary License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
15
16
|
Classifier: Programming Language :: Python :: 3
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
17
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
18
21
|
Requires-Python: >=3.13
|
|
19
22
|
Requires-Dist: httpx>=0.24.0
|
|
20
23
|
Requires-Dist: jinja2>=3.0.0
|
|
@@ -108,6 +111,6 @@ For the service's official API docs, see the [Greenhouse API reference](https://
|
|
|
108
111
|
|
|
109
112
|
## Version information
|
|
110
113
|
|
|
111
|
-
- **Package version:** 0.17.
|
|
114
|
+
- **Package version:** 0.17.40
|
|
112
115
|
- **Connector version:** 0.1.2
|
|
113
|
-
- **Generated with Connector SDK commit SHA:**
|
|
116
|
+
- **Generated with Connector SDK commit SHA:** b7138b411130e18a6ece05c58de092aa28ca0474
|
|
@@ -78,6 +78,6 @@ For the service's official API docs, see the [Greenhouse API reference](https://
|
|
|
78
78
|
|
|
79
79
|
## Version information
|
|
80
80
|
|
|
81
|
-
- **Package version:** 0.17.
|
|
81
|
+
- **Package version:** 0.17.40
|
|
82
82
|
- **Connector version:** 0.1.2
|
|
83
|
-
- **Generated with Connector SDK commit SHA:**
|
|
83
|
+
- **Generated with Connector SDK commit SHA:** b7138b411130e18a6ece05c58de092aa28ca0474
|
|
@@ -45,4 +45,41 @@ from .types import (
|
|
|
45
45
|
CandidateAttachmentDownloadParams
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
-
__all__ = [
|
|
48
|
+
__all__ = [
|
|
49
|
+
"GreenhouseConnector",
|
|
50
|
+
"GreenhouseAuthConfig",
|
|
51
|
+
"Attachment",
|
|
52
|
+
"Candidate",
|
|
53
|
+
"Application",
|
|
54
|
+
"Job",
|
|
55
|
+
"Offer",
|
|
56
|
+
"User",
|
|
57
|
+
"Department",
|
|
58
|
+
"Office",
|
|
59
|
+
"JobPost",
|
|
60
|
+
"Source",
|
|
61
|
+
"ScheduledInterview",
|
|
62
|
+
"GreenhouseExecuteResult",
|
|
63
|
+
"GreenhouseExecuteResultWithMeta",
|
|
64
|
+
"CandidatesListParams",
|
|
65
|
+
"CandidatesGetParams",
|
|
66
|
+
"ApplicationsListParams",
|
|
67
|
+
"ApplicationsGetParams",
|
|
68
|
+
"JobsListParams",
|
|
69
|
+
"JobsGetParams",
|
|
70
|
+
"OffersListParams",
|
|
71
|
+
"OffersGetParams",
|
|
72
|
+
"UsersListParams",
|
|
73
|
+
"UsersGetParams",
|
|
74
|
+
"DepartmentsListParams",
|
|
75
|
+
"DepartmentsGetParams",
|
|
76
|
+
"OfficesListParams",
|
|
77
|
+
"OfficesGetParams",
|
|
78
|
+
"JobPostsListParams",
|
|
79
|
+
"JobPostsGetParams",
|
|
80
|
+
"SourcesListParams",
|
|
81
|
+
"ScheduledInterviewsListParams",
|
|
82
|
+
"ScheduledInterviewsGetParams",
|
|
83
|
+
"ApplicationAttachmentDownloadParams",
|
|
84
|
+
"CandidateAttachmentDownloadParams",
|
|
85
|
+
]
|
|
@@ -13,7 +13,7 @@ class AirbyteCloudClient:
|
|
|
13
13
|
|
|
14
14
|
Handles authentication, token caching, and API calls to:
|
|
15
15
|
- Get bearer tokens for authentication
|
|
16
|
-
- Look up
|
|
16
|
+
- Look up connectors for users
|
|
17
17
|
- Execute connectors via the cloud API
|
|
18
18
|
|
|
19
19
|
Example:
|
|
@@ -22,15 +22,15 @@ class AirbyteCloudClient:
|
|
|
22
22
|
client_secret="your-client-secret"
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
# Get a connector
|
|
26
|
-
|
|
25
|
+
# Get a connector ID
|
|
26
|
+
connector_id = await client.get_connector_id(
|
|
27
27
|
external_user_id="user-123",
|
|
28
|
-
connector_definition_id="
|
|
28
|
+
connector_definition_id="550e8400-e29b-41d4-a716-446655440000"
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
# Execute the connector
|
|
32
32
|
result = await client.execute_connector(
|
|
33
|
-
|
|
33
|
+
connector_id=connector_id,
|
|
34
34
|
entity="customers",
|
|
35
35
|
action="list",
|
|
36
36
|
params={"limit": 10}
|
|
@@ -105,37 +105,37 @@ class AirbyteCloudClient:
|
|
|
105
105
|
|
|
106
106
|
return access_token
|
|
107
107
|
|
|
108
|
-
async def
|
|
108
|
+
async def get_connector_id(
|
|
109
109
|
self,
|
|
110
110
|
external_user_id: str,
|
|
111
111
|
connector_definition_id: str,
|
|
112
112
|
) -> str:
|
|
113
|
-
"""Get connector
|
|
113
|
+
"""Get connector ID for a user.
|
|
114
114
|
|
|
115
|
-
Looks up the connector
|
|
116
|
-
and connector definition. Validates that exactly one
|
|
115
|
+
Looks up the connector that belongs to the specified user
|
|
116
|
+
and connector definition. Validates that exactly one connector exists.
|
|
117
117
|
|
|
118
118
|
Args:
|
|
119
119
|
external_user_id: User identifier in the Airbyte system
|
|
120
120
|
connector_definition_id: UUID of the connector definition
|
|
121
121
|
|
|
122
122
|
Returns:
|
|
123
|
-
Connector
|
|
123
|
+
Connector ID (UUID string)
|
|
124
124
|
|
|
125
125
|
Raises:
|
|
126
|
-
ValueError: If 0 or more than 1
|
|
126
|
+
ValueError: If 0 or more than 1 connector is found
|
|
127
127
|
httpx.HTTPStatusError: If API returns 4xx/5xx status code
|
|
128
128
|
httpx.RequestError: If network request fails
|
|
129
129
|
|
|
130
130
|
Example:
|
|
131
|
-
|
|
131
|
+
connector_id = await client.get_connector_id(
|
|
132
132
|
external_user_id="user-123",
|
|
133
133
|
connector_definition_id="550e8400-e29b-41d4-a716-446655440000"
|
|
134
134
|
)
|
|
135
135
|
"""
|
|
136
136
|
|
|
137
137
|
token = await self.get_bearer_token()
|
|
138
|
-
url = f"{self.API_BASE_URL}/api/v1/connectors/
|
|
138
|
+
url = f"{self.API_BASE_URL}/api/v1/connectors/connectors_for_user"
|
|
139
139
|
params = {
|
|
140
140
|
"external_user_id": external_user_id,
|
|
141
141
|
"definition_id": connector_definition_id,
|
|
@@ -146,24 +146,24 @@ class AirbyteCloudClient:
|
|
|
146
146
|
response.raise_for_status()
|
|
147
147
|
|
|
148
148
|
data = response.json()
|
|
149
|
-
|
|
149
|
+
connectors = data["connectors"]
|
|
150
150
|
|
|
151
|
-
if len(
|
|
152
|
-
raise ValueError(f"No connector
|
|
151
|
+
if len(connectors) == 0:
|
|
152
|
+
raise ValueError(f"No connector found for user '{external_user_id}' and connector definition '{connector_definition_id}'")
|
|
153
153
|
|
|
154
|
-
if len(
|
|
154
|
+
if len(connectors) > 1:
|
|
155
155
|
raise ValueError(
|
|
156
|
-
f"Multiple
|
|
157
|
-
f"and connector '{connector_definition_id}'. Expected exactly 1, "
|
|
158
|
-
f"found {len(
|
|
156
|
+
f"Multiple connectors found for user '{external_user_id}' "
|
|
157
|
+
f"and connector definition '{connector_definition_id}'. Expected exactly 1, "
|
|
158
|
+
f"found {len(connectors)}"
|
|
159
159
|
)
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
return
|
|
161
|
+
connector_id = connectors[0]["id"]
|
|
162
|
+
return connector_id
|
|
163
163
|
|
|
164
164
|
async def execute_connector(
|
|
165
165
|
self,
|
|
166
|
-
|
|
166
|
+
connector_id: str,
|
|
167
167
|
entity: str,
|
|
168
168
|
action: str,
|
|
169
169
|
params: dict[str, Any] | None,
|
|
@@ -171,7 +171,7 @@ class AirbyteCloudClient:
|
|
|
171
171
|
"""Execute a connector operation.
|
|
172
172
|
|
|
173
173
|
Args:
|
|
174
|
-
|
|
174
|
+
connector_id: Connector UUID (source ID)
|
|
175
175
|
entity: Entity name (e.g., "customers", "invoices")
|
|
176
176
|
action: Operation action (e.g., "list", "get", "create")
|
|
177
177
|
params: Optional parameters for the operation
|
|
@@ -185,14 +185,14 @@ class AirbyteCloudClient:
|
|
|
185
185
|
|
|
186
186
|
Example:
|
|
187
187
|
result = await client.execute_connector(
|
|
188
|
-
|
|
188
|
+
connector_id="550e8400-e29b-41d4-a716-446655440000",
|
|
189
189
|
entity="customers",
|
|
190
190
|
action="list",
|
|
191
191
|
params={"limit": 10}
|
|
192
192
|
)
|
|
193
193
|
"""
|
|
194
194
|
token = await self.get_bearer_token()
|
|
195
|
-
url = f"{self.API_BASE_URL}/api/v1/connectors/
|
|
195
|
+
url = f"{self.API_BASE_URL}/api/v1/connectors/sources/{connector_id}/execute"
|
|
196
196
|
headers = {"Authorization": f"Bearer {token}"}
|
|
197
197
|
request_body = {
|
|
198
198
|
"entity": entity,
|
|
@@ -21,7 +21,7 @@ class HostedExecutor:
|
|
|
21
21
|
|
|
22
22
|
The executor takes an external_user_id and uses the AirbyteCloudClient to:
|
|
23
23
|
1. Authenticate with the Airbyte Platform (bearer token with caching)
|
|
24
|
-
2. Look up the user's connector
|
|
24
|
+
2. Look up the user's connector
|
|
25
25
|
3. Execute the connector operation via the cloud API
|
|
26
26
|
|
|
27
27
|
Implements ExecutorProtocol.
|
|
@@ -63,7 +63,7 @@ class HostedExecutor:
|
|
|
63
63
|
airbyte_client_id: Airbyte client ID for authentication
|
|
64
64
|
airbyte_client_secret: Airbyte client secret for authentication
|
|
65
65
|
connector_definition_id: Connector definition ID used to look up
|
|
66
|
-
the user's connector
|
|
66
|
+
the user's connector.
|
|
67
67
|
|
|
68
68
|
Example:
|
|
69
69
|
executor = HostedExecutor(
|
|
@@ -86,8 +86,8 @@ class HostedExecutor:
|
|
|
86
86
|
"""Execute connector via cloud API (ExecutorProtocol implementation).
|
|
87
87
|
|
|
88
88
|
Flow:
|
|
89
|
-
1. Get connector id from
|
|
90
|
-
2. Look up the user's connector
|
|
89
|
+
1. Get connector definition id from executor config
|
|
90
|
+
2. Look up the user's connector ID
|
|
91
91
|
3. Execute the connector operation via the cloud API
|
|
92
92
|
4. Parse the response into ExecutionResult
|
|
93
93
|
|
|
@@ -98,7 +98,7 @@ class HostedExecutor:
|
|
|
98
98
|
ExecutionResult with success/failure status
|
|
99
99
|
|
|
100
100
|
Raises:
|
|
101
|
-
ValueError: If no
|
|
101
|
+
ValueError: If no connector or multiple connectors found for user
|
|
102
102
|
httpx.HTTPStatusError: If API returns 4xx/5xx status code
|
|
103
103
|
httpx.RequestError: If network request fails
|
|
104
104
|
|
|
@@ -126,24 +126,23 @@ class HostedExecutor:
|
|
|
126
126
|
# Step 1: Get connector definition id
|
|
127
127
|
connector_definition_id = self._connector_definition_id
|
|
128
128
|
|
|
129
|
-
# Step 2: Get the connector
|
|
130
|
-
|
|
129
|
+
# Step 2: Get the connector ID for this user
|
|
130
|
+
connector_id = await self._cloud_client.get_connector_id(
|
|
131
131
|
external_user_id=self._external_user_id,
|
|
132
132
|
connector_definition_id=connector_definition_id,
|
|
133
133
|
)
|
|
134
134
|
|
|
135
|
-
span.set_attribute("connector.
|
|
135
|
+
span.set_attribute("connector.connector_id", connector_id)
|
|
136
136
|
|
|
137
137
|
# Step 3: Execute the connector via the cloud API
|
|
138
138
|
response = await self._cloud_client.execute_connector(
|
|
139
|
-
|
|
139
|
+
connector_id=connector_id,
|
|
140
140
|
entity=config.entity,
|
|
141
141
|
action=config.action,
|
|
142
142
|
params=config.params,
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
# Step 4: Parse the response into ExecutionResult
|
|
146
|
-
# The response_data is a dict from the API
|
|
147
146
|
result = self._parse_execution_result(response)
|
|
148
147
|
|
|
149
148
|
# Mark span as successful
|
|
@@ -152,7 +151,7 @@ class HostedExecutor:
|
|
|
152
151
|
return result
|
|
153
152
|
|
|
154
153
|
except ValueError as e:
|
|
155
|
-
#
|
|
154
|
+
# Connector lookup validation error (0 or >1 connectors)
|
|
156
155
|
span.set_attribute("connector.success", False)
|
|
157
156
|
span.set_attribute("connector.error_type", "ValueError")
|
|
158
157
|
span.record_exception(e)
|
|
@@ -1098,35 +1098,93 @@ class LocalExecutor:
|
|
|
1098
1098
|
|
|
1099
1099
|
return interpolate_value(variables)
|
|
1100
1100
|
|
|
1101
|
+
def _wrap_primitives(self, data: Any) -> dict[str, Any] | list[dict[str, Any]] | None:
|
|
1102
|
+
"""Wrap primitive values in dict format for consistent response structure.
|
|
1103
|
+
|
|
1104
|
+
Transforms primitive API responses into dict format so downstream code
|
|
1105
|
+
can always expect dict-based data structures.
|
|
1106
|
+
|
|
1107
|
+
Args:
|
|
1108
|
+
data: Response data (could be primitive, list, dict, or None)
|
|
1109
|
+
|
|
1110
|
+
Returns:
|
|
1111
|
+
- If data is a primitive (str, int, float, bool): {"value": data}
|
|
1112
|
+
- If data is a list: wraps all non-dict elements as {"value": item}
|
|
1113
|
+
- If data is already a dict or list of dicts: unchanged
|
|
1114
|
+
- If data is None: None
|
|
1115
|
+
|
|
1116
|
+
Examples:
|
|
1117
|
+
>>> executor._wrap_primitives(42)
|
|
1118
|
+
{"value": 42}
|
|
1119
|
+
>>> executor._wrap_primitives([1, 2, 3])
|
|
1120
|
+
[{"value": 1}, {"value": 2}, {"value": 3}]
|
|
1121
|
+
>>> executor._wrap_primitives([1, {"id": 2}, 3])
|
|
1122
|
+
[{"value": 1}, {"id": 2}, {"value": 3}]
|
|
1123
|
+
>>> executor._wrap_primitives([[1, 2], 3])
|
|
1124
|
+
[{"value": [1, 2]}, {"value": 3}]
|
|
1125
|
+
>>> executor._wrap_primitives({"id": 1})
|
|
1126
|
+
{"id": 1} # unchanged
|
|
1127
|
+
"""
|
|
1128
|
+
if data is None:
|
|
1129
|
+
return None
|
|
1130
|
+
|
|
1131
|
+
# Handle primitive scalars
|
|
1132
|
+
if isinstance(data, (bool, str, int, float)):
|
|
1133
|
+
return {"value": data}
|
|
1134
|
+
|
|
1135
|
+
# Handle lists - wrap non-dict elements
|
|
1136
|
+
if isinstance(data, list):
|
|
1137
|
+
if not data:
|
|
1138
|
+
return [] # Empty list unchanged
|
|
1139
|
+
|
|
1140
|
+
wrapped = []
|
|
1141
|
+
for item in data:
|
|
1142
|
+
if isinstance(item, dict):
|
|
1143
|
+
wrapped.append(item)
|
|
1144
|
+
else:
|
|
1145
|
+
wrapped.append({"value": item})
|
|
1146
|
+
return wrapped
|
|
1147
|
+
|
|
1148
|
+
# Dict - return unchanged
|
|
1149
|
+
if isinstance(data, dict):
|
|
1150
|
+
return data
|
|
1151
|
+
|
|
1152
|
+
# Unknown type - wrap for safety
|
|
1153
|
+
return {"value": data}
|
|
1154
|
+
|
|
1101
1155
|
def _extract_records(
|
|
1102
1156
|
self,
|
|
1103
|
-
response_data:
|
|
1157
|
+
response_data: Any,
|
|
1104
1158
|
endpoint: EndpointDefinition,
|
|
1105
|
-
) -> dict[str, Any] | list[Any] | None:
|
|
1159
|
+
) -> dict[str, Any] | list[dict[str, Any]] | None:
|
|
1106
1160
|
"""Extract records from response using record extractor.
|
|
1107
1161
|
|
|
1108
1162
|
Type inference based on action:
|
|
1109
1163
|
- list, search: Returns array ([] if not found)
|
|
1110
1164
|
- get, create, update, delete: Returns single record (None if not found)
|
|
1111
1165
|
|
|
1166
|
+
Automatically wraps primitive values (int, str, float, bool) in {"value": primitive}
|
|
1167
|
+
format to ensure consistent dict-based responses for downstream code.
|
|
1168
|
+
|
|
1112
1169
|
Args:
|
|
1113
|
-
response_data: Full API response
|
|
1170
|
+
response_data: Full API response (can be dict, list, primitive, or None)
|
|
1114
1171
|
endpoint: Endpoint with optional record extractor and action
|
|
1115
1172
|
|
|
1116
1173
|
Returns:
|
|
1117
1174
|
- Extracted data if extractor configured and path found
|
|
1118
1175
|
- [] or None if path not found (based on action)
|
|
1119
1176
|
- Original response if no extractor configured or on error
|
|
1177
|
+
- Primitives are wrapped as {"value": primitive}
|
|
1120
1178
|
"""
|
|
1121
1179
|
# Check if endpoint has record extractor
|
|
1122
1180
|
extractor = endpoint.record_extractor
|
|
1123
1181
|
if not extractor:
|
|
1124
|
-
return response_data
|
|
1182
|
+
return self._wrap_primitives(response_data)
|
|
1125
1183
|
|
|
1126
1184
|
# Determine if this action returns array or single record
|
|
1127
1185
|
action = endpoint.action
|
|
1128
1186
|
if not action:
|
|
1129
|
-
return response_data
|
|
1187
|
+
return self._wrap_primitives(response_data)
|
|
1130
1188
|
|
|
1131
1189
|
is_array_action = action in (Action.LIST, Action.API_SEARCH)
|
|
1132
1190
|
|
|
@@ -1139,17 +1197,19 @@ class LocalExecutor:
|
|
|
1139
1197
|
# Path not found - return empty based on action
|
|
1140
1198
|
return [] if is_array_action else None
|
|
1141
1199
|
|
|
1142
|
-
# Return extracted data
|
|
1200
|
+
# Return extracted data with primitive wrapping
|
|
1143
1201
|
if is_array_action:
|
|
1144
1202
|
# For array actions, return the array (or list of matches)
|
|
1145
|
-
|
|
1203
|
+
result = matches[0] if len(matches) == 1 else matches
|
|
1146
1204
|
else:
|
|
1147
1205
|
# For single record actions, return first match
|
|
1148
|
-
|
|
1206
|
+
result = matches[0]
|
|
1207
|
+
|
|
1208
|
+
return self._wrap_primitives(result)
|
|
1149
1209
|
|
|
1150
1210
|
except Exception as e:
|
|
1151
1211
|
logging.warning(f"Failed to apply record extractor '{extractor}': {e}. Returning original response.")
|
|
1152
|
-
return response_data
|
|
1212
|
+
return self._wrap_primitives(response_data)
|
|
1153
1213
|
|
|
1154
1214
|
def _extract_metadata(
|
|
1155
1215
|
self,
|
|
@@ -7,6 +7,7 @@ References:
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
from collections.abc import Iterator
|
|
10
11
|
from typing import Any
|
|
11
12
|
|
|
12
13
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
@@ -15,7 +16,7 @@ from ..constants import OPENAPI_VERSION_PREFIX
|
|
|
15
16
|
|
|
16
17
|
from .base import Info, Server
|
|
17
18
|
from .components import Components
|
|
18
|
-
from .operations import PathItem
|
|
19
|
+
from .operations import Operation, PathItem
|
|
19
20
|
from .security import SecurityRequirement
|
|
20
21
|
|
|
21
22
|
|
|
@@ -33,6 +34,10 @@ class Tag(BaseModel):
|
|
|
33
34
|
external_docs: dict[str, Any] | None = Field(None, alias="externalDocs")
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
# HTTP methods supported by OpenAPI operations
|
|
38
|
+
HTTP_METHODS = frozenset({"get", "post", "put", "patch", "delete", "options", "head", "trace"})
|
|
39
|
+
|
|
40
|
+
|
|
36
41
|
class ExternalDocs(BaseModel):
|
|
37
42
|
"""
|
|
38
43
|
External documentation reference.
|
|
@@ -79,7 +84,7 @@ class OpenAPIConnector(BaseModel):
|
|
|
79
84
|
raise ValueError(f"OpenAPI version must be {OPENAPI_VERSION_PREFIX}x, got: {v}")
|
|
80
85
|
return v
|
|
81
86
|
|
|
82
|
-
def get_entity_operations(self, entity_name: str) -> list[tuple[str, str,
|
|
87
|
+
def get_entity_operations(self, entity_name: str) -> list[tuple[str, str, Operation]]:
|
|
83
88
|
"""
|
|
84
89
|
Get all operations for a specific entity.
|
|
85
90
|
|
|
@@ -89,22 +94,7 @@ class OpenAPIConnector(BaseModel):
|
|
|
89
94
|
Returns:
|
|
90
95
|
List of tuples: (path, method, operation)
|
|
91
96
|
"""
|
|
92
|
-
|
|
93
|
-
for path, path_item in self.paths.items():
|
|
94
|
-
for method in [
|
|
95
|
-
"get",
|
|
96
|
-
"post",
|
|
97
|
-
"put",
|
|
98
|
-
"patch",
|
|
99
|
-
"delete",
|
|
100
|
-
"options",
|
|
101
|
-
"head",
|
|
102
|
-
"trace",
|
|
103
|
-
]:
|
|
104
|
-
operation = getattr(path_item, method, None)
|
|
105
|
-
if operation and operation.x_airbyte_entity == entity_name:
|
|
106
|
-
results.append((path, method, operation))
|
|
107
|
-
return results
|
|
97
|
+
return [(path, method, op) for path, method, op in self._iter_operations() if op.x_airbyte_entity == entity_name]
|
|
108
98
|
|
|
109
99
|
def list_entities(self) -> list[str]:
|
|
110
100
|
"""
|
|
@@ -113,19 +103,18 @@ class OpenAPIConnector(BaseModel):
|
|
|
113
103
|
Returns:
|
|
114
104
|
Sorted list of unique entity names
|
|
115
105
|
"""
|
|
116
|
-
entities =
|
|
117
|
-
for path_item in self.paths.values():
|
|
118
|
-
for method in [
|
|
119
|
-
"get",
|
|
120
|
-
"post",
|
|
121
|
-
"put",
|
|
122
|
-
"patch",
|
|
123
|
-
"delete",
|
|
124
|
-
"options",
|
|
125
|
-
"head",
|
|
126
|
-
"trace",
|
|
127
|
-
]:
|
|
128
|
-
operation = getattr(path_item, method, None)
|
|
129
|
-
if operation and operation.x_airbyte_entity:
|
|
130
|
-
entities.add(operation.x_airbyte_entity)
|
|
106
|
+
entities = {op.x_airbyte_entity for _, _, op in self._iter_operations() if op.x_airbyte_entity}
|
|
131
107
|
return sorted(entities)
|
|
108
|
+
|
|
109
|
+
def _iter_operations(self) -> Iterator[tuple[str, str, Operation]]:
|
|
110
|
+
"""
|
|
111
|
+
Iterate over all operations in the spec.
|
|
112
|
+
|
|
113
|
+
Yields:
|
|
114
|
+
Tuples of (path, method, operation) for each defined operation
|
|
115
|
+
"""
|
|
116
|
+
for path, path_item in self.paths.items():
|
|
117
|
+
for method in HTTP_METHODS:
|
|
118
|
+
operation = getattr(path_item, method, None)
|
|
119
|
+
if operation:
|
|
120
|
+
yield path, method, operation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "airbyte-agent-greenhouse"
|
|
3
|
-
version = "0.17.
|
|
3
|
+
version = "0.17.40"
|
|
4
4
|
description = "Airbyte Greenhouse Connector for AI platforms"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
@@ -8,14 +8,17 @@ license = {text = "Elastic-2.0"}
|
|
|
8
8
|
authors = [
|
|
9
9
|
{name = "Airbyte", email = "contact@airbyte.io"}
|
|
10
10
|
]
|
|
11
|
-
keywords = ["airbyte", "greenhouse", "connector", "api"]
|
|
11
|
+
keywords = ["airbyte", "greenhouse", "connector", "api", "ai", "agent", "llm", "mcp", "data-integration"]
|
|
12
12
|
classifiers = [
|
|
13
13
|
"Development Status :: 3 - Alpha",
|
|
14
14
|
"Intended Audience :: Developers",
|
|
15
15
|
"License :: Other/Proprietary License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
16
17
|
"Programming Language :: Python :: 3",
|
|
17
18
|
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
18
20
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
|
+
"Typing :: Typed",
|
|
19
22
|
]
|
|
20
23
|
dependencies = [
|
|
21
24
|
"httpx>=0.24.0",
|
|
@@ -31,10 +34,10 @@ dependencies = [
|
|
|
31
34
|
]
|
|
32
35
|
|
|
33
36
|
[project.urls]
|
|
34
|
-
Homepage = "https://github.com/airbytehq/airbyte-
|
|
35
|
-
Documentation = "https://
|
|
36
|
-
Repository = "https://github.com/airbytehq/airbyte-
|
|
37
|
-
Issues = "https://github.com/airbytehq/airbyte-
|
|
37
|
+
Homepage = "https://github.com/airbytehq/airbyte-agent-connectors"
|
|
38
|
+
Documentation = "https://docs.airbyte.com/ai-agents/"
|
|
39
|
+
Repository = "https://github.com/airbytehq/airbyte-agent-connectors"
|
|
40
|
+
Issues = "https://github.com/airbytehq/airbyte-agent-connectors/issues"
|
|
38
41
|
|
|
39
42
|
[build-system]
|
|
40
43
|
requires = ["hatchling"]
|
|
@@ -44,4 +47,4 @@ build-backend = "hatchling.build"
|
|
|
44
47
|
packages = ["airbyte_agent_greenhouse"]
|
|
45
48
|
|
|
46
49
|
[tool.hatch.build.targets.wheel.shared-data]
|
|
47
|
-
"airbyte_agent_greenhouse/connector.yaml" = "share/airbyte_agent_greenhouse/connector.yaml"
|
|
50
|
+
"airbyte_agent_greenhouse/connector.yaml" = "share/airbyte_agent_greenhouse/connector.yaml"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|