airbyte-agent-zendesk-support 0.18.59__tar.gz → 0.18.61__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_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/AUTH.md +1 -1
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/CHANGELOG.md +10 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/PKG-INFO +7 -6
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/README.md +6 -5
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/REFERENCE.md +15 -14
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/connector_model_loader.py +84 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/local_executor.py +3 -1
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/introspection.py +222 -10
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/base.py +3 -1
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/components.py +5 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/extensions.py +71 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/types.py +1 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/connector.py +101 -39
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/connector_model.py +287 -1
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/models.py +7 -7
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/types.py +35 -35
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/pyproject.toml +1 -1
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/.gitignore +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_strategies.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_template.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/client.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/constants.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/exceptions.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/hosted_executor.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/models.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/extensions.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/adapters/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/adapters/httpx_adapter.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/config.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/exceptions.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/protocols.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http/response.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/http_client.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/logger.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/types.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/config.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/models.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/redactor.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/session.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/instrumentation.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/metrics.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/connector.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/operations.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/security.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/secrets.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/__init__.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/config.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/events.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/tracker.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/utils.py +0 -0
- {airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/airbyte_agent_zendesk_support/_vendored/connector_sdk/validation.py +0 -0
|
@@ -103,7 +103,7 @@ connector = ZendeskSupportConnector(
|
|
|
103
103
|
)
|
|
104
104
|
|
|
105
105
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
106
|
-
@ZendeskSupportConnector.
|
|
106
|
+
@ZendeskSupportConnector.tool_utils
|
|
107
107
|
async def zendesk-support_execute(entity: str, action: str, params: dict | None = None):
|
|
108
108
|
return await connector.execute(entity, action, params or {})
|
|
109
109
|
```
|
{airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/CHANGELOG.md
RENAMED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Zendesk Support changelog
|
|
2
2
|
|
|
3
|
+
## [0.18.61] - 2026-01-24
|
|
4
|
+
- Updated connector definition (YAML version 0.1.8)
|
|
5
|
+
- Source commit: 609c1d86
|
|
6
|
+
- SDK version: 0.1.0
|
|
7
|
+
|
|
8
|
+
## [0.18.60] - 2026-01-23
|
|
9
|
+
- Updated connector definition (YAML version 0.1.8)
|
|
10
|
+
- Source commit: 592446b8
|
|
11
|
+
- SDK version: 0.1.0
|
|
12
|
+
|
|
3
13
|
## [0.18.59] - 2026-01-23
|
|
4
14
|
- Updated connector definition (YAML version 0.1.7)
|
|
5
15
|
- Source commit: 416466da
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-zendesk-support
|
|
3
|
-
Version: 0.18.
|
|
3
|
+
Version: 0.18.61
|
|
4
4
|
Summary: Airbyte Zendesk-Support Connector for AI platforms
|
|
5
5
|
Project-URL: Homepage, https://github.com/airbytehq/airbyte-agent-connectors
|
|
6
6
|
Project-URL: Documentation, https://docs.airbyte.com/ai-agents/
|
|
@@ -89,7 +89,7 @@ connector = ZendeskSupportConnector(
|
|
|
89
89
|
)
|
|
90
90
|
|
|
91
91
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
92
|
-
@ZendeskSupportConnector.
|
|
92
|
+
@ZendeskSupportConnector.tool_utils
|
|
93
93
|
async def zendesk-support_execute(entity: str, action: str, params: dict | None = None):
|
|
94
94
|
return await connector.execute(entity, action, params or {})
|
|
95
95
|
```
|
|
@@ -110,11 +110,12 @@ connector = ZendeskSupportConnector(
|
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
113
|
-
@ZendeskSupportConnector.
|
|
113
|
+
@ZendeskSupportConnector.tool_utils
|
|
114
114
|
async def zendesk-support_execute(entity: str, action: str, params: dict | None = None):
|
|
115
115
|
return await connector.execute(entity, action, params or {})
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
|
|
118
119
|
## Full documentation
|
|
119
120
|
|
|
120
121
|
This connector supports the following entities and actions.
|
|
@@ -153,6 +154,6 @@ For the service's official API docs, see the [Zendesk-Support API reference](htt
|
|
|
153
154
|
|
|
154
155
|
## Version information
|
|
155
156
|
|
|
156
|
-
- **Package version:** 0.18.
|
|
157
|
-
- **Connector version:** 0.1.
|
|
158
|
-
- **Generated with Connector SDK commit SHA:**
|
|
157
|
+
- **Package version:** 0.18.61
|
|
158
|
+
- **Connector version:** 0.1.8
|
|
159
|
+
- **Generated with Connector SDK commit SHA:** 609c1d86c76b36ff699b57123a5a8c2050d958c3
|
|
@@ -56,7 +56,7 @@ connector = ZendeskSupportConnector(
|
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
59
|
-
@ZendeskSupportConnector.
|
|
59
|
+
@ZendeskSupportConnector.tool_utils
|
|
60
60
|
async def zendesk-support_execute(entity: str, action: str, params: dict | None = None):
|
|
61
61
|
return await connector.execute(entity, action, params or {})
|
|
62
62
|
```
|
|
@@ -77,11 +77,12 @@ connector = ZendeskSupportConnector(
|
|
|
77
77
|
)
|
|
78
78
|
|
|
79
79
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
80
|
-
@ZendeskSupportConnector.
|
|
80
|
+
@ZendeskSupportConnector.tool_utils
|
|
81
81
|
async def zendesk-support_execute(entity: str, action: str, params: dict | None = None):
|
|
82
82
|
return await connector.execute(entity, action, params or {})
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
|
|
85
86
|
## Full documentation
|
|
86
87
|
|
|
87
88
|
This connector supports the following entities and actions.
|
|
@@ -120,6 +121,6 @@ For the service's official API docs, see the [Zendesk-Support API reference](htt
|
|
|
120
121
|
|
|
121
122
|
## Version information
|
|
122
123
|
|
|
123
|
-
- **Package version:** 0.18.
|
|
124
|
-
- **Connector version:** 0.1.
|
|
125
|
-
- **Generated with Connector SDK commit SHA:**
|
|
124
|
+
- **Package version:** 0.18.61
|
|
125
|
+
- **Connector version:** 0.1.8
|
|
126
|
+
- **Generated with Connector SDK commit SHA:** 609c1d86c76b36ff699b57123a5a8c2050d958c3
|
{airbyte_agent_zendesk_support-0.18.59 → airbyte_agent_zendesk_support-0.18.61}/REFERENCE.md
RENAMED
|
@@ -258,7 +258,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
258
258
|
| `created_at` | `string` | Timestamp indicating when the ticket was created |
|
|
259
259
|
| `custom_fields` | `array` | Array of custom field values specific to the account's ticket configuration |
|
|
260
260
|
| `custom_status_id` | `integer` | Unique identifier of the custom status applied to the ticket |
|
|
261
|
-
| `deleted_ticket_form_id` | `integer` |
|
|
261
|
+
| `deleted_ticket_form_id` | `integer` | The ID of the ticket form that was previously associated with this ticket but has since been deleted |
|
|
262
262
|
| `description` | `string` | Initial description or content of the ticket when it was created |
|
|
263
263
|
| `due_at` | `string` | Timestamp indicating when the ticket is due for completion or resolution |
|
|
264
264
|
| `email_cc_ids` | `array` | Array of user identifiers who are CC'd on ticket email notifications |
|
|
@@ -268,7 +268,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
268
268
|
| `followup_ids` | `array` | Array of identifiers for follow-up tickets related to this ticket |
|
|
269
269
|
| `forum_topic_id` | `integer` | Unique identifier linking the ticket to a forum topic if applicable |
|
|
270
270
|
| `from_messaging_channel` | `boolean` | Boolean indicating whether the ticket originated from a messaging channel |
|
|
271
|
-
| `generated_timestamp` | `integer` | Timestamp updated for all ticket updates including system changes, used for incremental export
|
|
271
|
+
| `generated_timestamp` | `integer` | Timestamp updated for all ticket updates including system changes, used for incremental export |
|
|
272
272
|
| `group_id` | `integer` | Unique identifier of the agent group assigned to handle the ticket |
|
|
273
273
|
| `has_incidents` | `boolean` | Boolean indicating whether this problem ticket has related incident tickets |
|
|
274
274
|
| `id` | `integer` | Unique identifier for the ticket |
|
|
@@ -308,7 +308,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
308
308
|
| `hits[].data.created_at` | `string` | Timestamp indicating when the ticket was created |
|
|
309
309
|
| `hits[].data.custom_fields` | `array` | Array of custom field values specific to the account's ticket configuration |
|
|
310
310
|
| `hits[].data.custom_status_id` | `integer` | Unique identifier of the custom status applied to the ticket |
|
|
311
|
-
| `hits[].data.deleted_ticket_form_id` | `integer` |
|
|
311
|
+
| `hits[].data.deleted_ticket_form_id` | `integer` | The ID of the ticket form that was previously associated with this ticket but has since been deleted |
|
|
312
312
|
| `hits[].data.description` | `string` | Initial description or content of the ticket when it was created |
|
|
313
313
|
| `hits[].data.due_at` | `string` | Timestamp indicating when the ticket is due for completion or resolution |
|
|
314
314
|
| `hits[].data.email_cc_ids` | `array` | Array of user identifiers who are CC'd on ticket email notifications |
|
|
@@ -318,7 +318,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
318
318
|
| `hits[].data.followup_ids` | `array` | Array of identifiers for follow-up tickets related to this ticket |
|
|
319
319
|
| `hits[].data.forum_topic_id` | `integer` | Unique identifier linking the ticket to a forum topic if applicable |
|
|
320
320
|
| `hits[].data.from_messaging_channel` | `boolean` | Boolean indicating whether the ticket originated from a messaging channel |
|
|
321
|
-
| `hits[].data.generated_timestamp` | `integer` | Timestamp updated for all ticket updates including system changes, used for incremental export
|
|
321
|
+
| `hits[].data.generated_timestamp` | `integer` | Timestamp updated for all ticket updates including system changes, used for incremental export |
|
|
322
322
|
| `hits[].data.group_id` | `integer` | Unique identifier of the agent group assigned to handle the ticket |
|
|
323
323
|
| `hits[].data.has_incidents` | `boolean` | Boolean indicating whether this problem ticket has related incident tickets |
|
|
324
324
|
| `hits[].data.id` | `integer` | Unique identifier for the ticket |
|
|
@@ -1894,9 +1894,9 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
1894
1894
|
|------------|------|-------------|
|
|
1895
1895
|
| `active` | `boolean` | Whether this field is currently available for use |
|
|
1896
1896
|
| `agent_description` | `string` | A description of the ticket field that only agents can see |
|
|
1897
|
-
| `collapsed_for_agents` | `boolean` | If true, the field is shown to agents by default; if false, it is hidden alongside infrequently
|
|
1897
|
+
| `collapsed_for_agents` | `boolean` | If true, the field is shown to agents by default; if false, it is hidden alongside infrequently used fields |
|
|
1898
1898
|
| `created_at` | `string` | Timestamp when the custom ticket field was created |
|
|
1899
|
-
| `custom_field_options` | `array` | Array of option objects for custom ticket fields of type multiselect or tagger
|
|
1899
|
+
| `custom_field_options` | `array` | Array of option objects for custom ticket fields of type multiselect or tagger |
|
|
1900
1900
|
| `custom_statuses` | `array` | List of customized ticket statuses, only present for system ticket fields of type custom_status |
|
|
1901
1901
|
| `description` | `string` | Text describing the purpose of the ticket field to users |
|
|
1902
1902
|
| `editable_in_portal` | `boolean` | Whether this field is editable by end users in Help Center |
|
|
@@ -1915,7 +1915,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
1915
1915
|
| `tag` | `string` | For checkbox fields only, a tag added to tickets when the checkbox field is selected |
|
|
1916
1916
|
| `title` | `string` | The title of the ticket field displayed to agents |
|
|
1917
1917
|
| `title_in_portal` | `string` | The title of the ticket field displayed to end users in Help Center |
|
|
1918
|
-
| `type` | `string` | Field type such as text, textarea, checkbox, date, integer, decimal, regexp, multiselect, tagger
|
|
1918
|
+
| `type` | `string` | Field type such as text, textarea, checkbox, date, integer, decimal, regexp, multiselect, or tagger |
|
|
1919
1919
|
| `updated_at` | `string` | Timestamp when the custom ticket field was last updated |
|
|
1920
1920
|
| `url` | `string` | The API URL for this ticket field resource |
|
|
1921
1921
|
| `visible_in_portal` | `boolean` | Whether this field is visible to end users in Help Center |
|
|
@@ -1931,9 +1931,9 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
1931
1931
|
| `hits[].data` | `object` | Record data containing the searchable fields listed above |
|
|
1932
1932
|
| `hits[].data.active` | `boolean` | Whether this field is currently available for use |
|
|
1933
1933
|
| `hits[].data.agent_description` | `string` | A description of the ticket field that only agents can see |
|
|
1934
|
-
| `hits[].data.collapsed_for_agents` | `boolean` | If true, the field is shown to agents by default; if false, it is hidden alongside infrequently
|
|
1934
|
+
| `hits[].data.collapsed_for_agents` | `boolean` | If true, the field is shown to agents by default; if false, it is hidden alongside infrequently used fields |
|
|
1935
1935
|
| `hits[].data.created_at` | `string` | Timestamp when the custom ticket field was created |
|
|
1936
|
-
| `hits[].data.custom_field_options` | `array` | Array of option objects for custom ticket fields of type multiselect or tagger
|
|
1936
|
+
| `hits[].data.custom_field_options` | `array` | Array of option objects for custom ticket fields of type multiselect or tagger |
|
|
1937
1937
|
| `hits[].data.custom_statuses` | `array` | List of customized ticket statuses, only present for system ticket fields of type custom_status |
|
|
1938
1938
|
| `hits[].data.description` | `string` | Text describing the purpose of the ticket field to users |
|
|
1939
1939
|
| `hits[].data.editable_in_portal` | `boolean` | Whether this field is editable by end users in Help Center |
|
|
@@ -1952,7 +1952,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
1952
1952
|
| `hits[].data.tag` | `string` | For checkbox fields only, a tag added to tickets when the checkbox field is selected |
|
|
1953
1953
|
| `hits[].data.title` | `string` | The title of the ticket field displayed to agents |
|
|
1954
1954
|
| `hits[].data.title_in_portal` | `string` | The title of the ticket field displayed to end users in Help Center |
|
|
1955
|
-
| `hits[].data.type` | `string` | Field type such as text, textarea, checkbox, date, integer, decimal, regexp, multiselect, tagger
|
|
1955
|
+
| `hits[].data.type` | `string` | Field type such as text, textarea, checkbox, date, integer, decimal, regexp, multiselect, or tagger |
|
|
1956
1956
|
| `hits[].data.updated_at` | `string` | Timestamp when the custom ticket field was last updated |
|
|
1957
1957
|
| `hits[].data.url` | `string` | The API URL for this ticket field resource |
|
|
1958
1958
|
| `hits[].data.visible_in_portal` | `boolean` | Whether this field is visible to end users in Help Center |
|
|
@@ -2962,7 +2962,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
2962
2962
|
| `group_id` | `integer` | The identifier of the group assigned to the ticket at the time the rating was submitted |
|
|
2963
2963
|
| `id` | `integer` | Unique identifier for the satisfaction rating, automatically assigned upon creation |
|
|
2964
2964
|
| `reason` | `string` | Free-text reason for a bad rating provided by the requester in a follow-up question |
|
|
2965
|
-
| `reason_id` | `integer` | Identifier for the predefined reason given for a negative rating
|
|
2965
|
+
| `reason_id` | `integer` | Identifier for the predefined reason given for a negative rating |
|
|
2966
2966
|
| `requester_id` | `integer` | The identifier of the ticket requester who submitted the satisfaction rating |
|
|
2967
2967
|
| `score` | `string` | The satisfaction rating value: 'offered', 'unoffered', 'good', or 'bad' |
|
|
2968
2968
|
| `ticket_id` | `integer` | The identifier of the ticket being rated |
|
|
@@ -2984,7 +2984,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
2984
2984
|
| `hits[].data.group_id` | `integer` | The identifier of the group assigned to the ticket at the time the rating was submitted |
|
|
2985
2985
|
| `hits[].data.id` | `integer` | Unique identifier for the satisfaction rating, automatically assigned upon creation |
|
|
2986
2986
|
| `hits[].data.reason` | `string` | Free-text reason for a bad rating provided by the requester in a follow-up question |
|
|
2987
|
-
| `hits[].data.reason_id` | `integer` | Identifier for the predefined reason given for a negative rating
|
|
2987
|
+
| `hits[].data.reason_id` | `integer` | Identifier for the predefined reason given for a negative rating |
|
|
2988
2988
|
| `hits[].data.requester_id` | `integer` | The identifier of the ticket requester who submitted the satisfaction rating |
|
|
2989
2989
|
| `hits[].data.score` | `string` | The satisfaction rating value: 'offered', 'unoffered', 'good', or 'bad' |
|
|
2990
2990
|
| `hits[].data.ticket_id` | `integer` | The identifier of the ticket being rated |
|
|
@@ -3417,7 +3417,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
3417
3417
|
| `raw_display_name` | `string` | The dynamic content placeholder if present, or the display_name value if not |
|
|
3418
3418
|
| `raw_name` | `string` | The dynamic content placeholder if present, or the name value if not |
|
|
3419
3419
|
| `restricted_brand_ids` | `array` | IDs of all brands that this ticket form is restricted to |
|
|
3420
|
-
| `ticket_field_ids` | `array` | IDs of all ticket fields included in this ticket form
|
|
3420
|
+
| `ticket_field_ids` | `array` | IDs of all ticket fields included in this ticket form |
|
|
3421
3421
|
| `updated_at` | `string` | Timestamp of the last update to the ticket form |
|
|
3422
3422
|
| `url` | `string` | URL of the ticket form |
|
|
3423
3423
|
|
|
@@ -3444,7 +3444,7 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
3444
3444
|
| `hits[].data.raw_display_name` | `string` | The dynamic content placeholder if present, or the display_name value if not |
|
|
3445
3445
|
| `hits[].data.raw_name` | `string` | The dynamic content placeholder if present, or the name value if not |
|
|
3446
3446
|
| `hits[].data.restricted_brand_ids` | `array` | IDs of all brands that this ticket form is restricted to |
|
|
3447
|
-
| `hits[].data.ticket_field_ids` | `array` | IDs of all ticket fields included in this ticket form
|
|
3447
|
+
| `hits[].data.ticket_field_ids` | `array` | IDs of all ticket fields included in this ticket form |
|
|
3448
3448
|
| `hits[].data.updated_at` | `string` | Timestamp of the last update to the ticket form |
|
|
3449
3449
|
| `hits[].data.url` | `string` | URL of the ticket form |
|
|
3450
3450
|
| `next_cursor` | `string \| null` | Cursor for next page of results |
|
|
@@ -3748,3 +3748,4 @@ curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_i
|
|
|
3748
3748
|
| `range_header` | `string` | No | Optional Range header for partial downloads (e.g., 'bytes=0-99') |
|
|
3749
3749
|
|
|
3750
3750
|
|
|
3751
|
+
|
|
@@ -145,6 +145,87 @@ def _deproxy_schema(obj: Any) -> Any:
|
|
|
145
145
|
return obj
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
def _type_includes(type_value: Any, target: str) -> bool:
|
|
149
|
+
if isinstance(type_value, list):
|
|
150
|
+
return target in type_value
|
|
151
|
+
return type_value == target
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _flatten_cache_properties(properties: dict[str, Any], prefix: str) -> list[str]:
|
|
155
|
+
entries: list[str] = []
|
|
156
|
+
for prop_name, prop in properties.items():
|
|
157
|
+
path = f"{prefix}{prop_name}" if prefix else prop_name
|
|
158
|
+
entries.append(path)
|
|
159
|
+
|
|
160
|
+
prop_type = getattr(prop, "type", None) if not isinstance(prop, dict) else prop.get("type")
|
|
161
|
+
prop_properties = getattr(prop, "properties", None) if not isinstance(prop, dict) else prop.get("properties")
|
|
162
|
+
|
|
163
|
+
if _type_includes(prop_type, "array"):
|
|
164
|
+
array_path = f"{path}[]"
|
|
165
|
+
entries.append(array_path)
|
|
166
|
+
if isinstance(prop_properties, dict):
|
|
167
|
+
entries.extend(_flatten_cache_properties(prop_properties, prefix=f"{array_path}."))
|
|
168
|
+
elif isinstance(prop_properties, dict):
|
|
169
|
+
entries.extend(_flatten_cache_properties(prop_properties, prefix=f"{path}."))
|
|
170
|
+
|
|
171
|
+
return entries
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _flatten_cache_field_paths(field: Any) -> list[str]:
|
|
175
|
+
field_name = getattr(field, "name", None) if not isinstance(field, dict) else field.get("name")
|
|
176
|
+
if not isinstance(field_name, str) or not field_name:
|
|
177
|
+
return []
|
|
178
|
+
|
|
179
|
+
field_type = getattr(field, "type", None) if not isinstance(field, dict) else field.get("type")
|
|
180
|
+
field_properties = getattr(field, "properties", None) if not isinstance(field, dict) else field.get("properties")
|
|
181
|
+
|
|
182
|
+
entries = [field_name]
|
|
183
|
+
if _type_includes(field_type, "array"):
|
|
184
|
+
array_path = f"{field_name}[]"
|
|
185
|
+
entries.append(array_path)
|
|
186
|
+
if isinstance(field_properties, dict):
|
|
187
|
+
entries.extend(_flatten_cache_properties(field_properties, prefix=f"{array_path}."))
|
|
188
|
+
elif isinstance(field_properties, dict):
|
|
189
|
+
entries.extend(_flatten_cache_properties(field_properties, prefix=f"{field_name}."))
|
|
190
|
+
|
|
191
|
+
return entries
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _dedupe_strings(values: list[str]) -> list[str]:
|
|
195
|
+
seen: set[str] = set()
|
|
196
|
+
ordered: list[str] = []
|
|
197
|
+
for value in values:
|
|
198
|
+
if value not in seen:
|
|
199
|
+
seen.add(value)
|
|
200
|
+
ordered.append(value)
|
|
201
|
+
return ordered
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _extract_search_field_paths(spec: OpenAPIConnector) -> dict[str, list[str]]:
|
|
205
|
+
cache_config = getattr(spec.info, "x_airbyte_cache", None)
|
|
206
|
+
entities = getattr(cache_config, "entities", None)
|
|
207
|
+
if not isinstance(entities, list):
|
|
208
|
+
return {}
|
|
209
|
+
|
|
210
|
+
search_fields: dict[str, list[str]] = {}
|
|
211
|
+
for entity in entities:
|
|
212
|
+
entity_name = getattr(entity, "entity", None) if not isinstance(entity, dict) else entity.get("entity")
|
|
213
|
+
if not isinstance(entity_name, str) or not entity_name:
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
fields = getattr(entity, "fields", None) if not isinstance(entity, dict) else entity.get("fields")
|
|
217
|
+
if not isinstance(fields, list):
|
|
218
|
+
continue
|
|
219
|
+
|
|
220
|
+
field_paths: list[str] = []
|
|
221
|
+
for field in fields:
|
|
222
|
+
field_paths.extend(_flatten_cache_field_paths(field))
|
|
223
|
+
|
|
224
|
+
search_fields[entity_name] = _dedupe_strings(field_paths)
|
|
225
|
+
|
|
226
|
+
return search_fields
|
|
227
|
+
|
|
228
|
+
|
|
148
229
|
def parse_openapi_spec(raw_config: dict) -> OpenAPIConnector:
|
|
149
230
|
"""Parse OpenAPI specification from YAML.
|
|
150
231
|
|
|
@@ -434,6 +515,8 @@ def convert_openapi_to_connector_model(spec: OpenAPIConnector) -> ConnectorModel
|
|
|
434
515
|
if not connector_id:
|
|
435
516
|
raise InvalidOpenAPIError("Missing required x-airbyte-connector-id field")
|
|
436
517
|
|
|
518
|
+
search_field_paths = _extract_search_field_paths(spec)
|
|
519
|
+
|
|
437
520
|
# Create ConnectorModel
|
|
438
521
|
model = ConnectorModel(
|
|
439
522
|
id=connector_id,
|
|
@@ -444,6 +527,7 @@ def convert_openapi_to_connector_model(spec: OpenAPIConnector) -> ConnectorModel
|
|
|
444
527
|
entities=entities,
|
|
445
528
|
openapi_spec=spec,
|
|
446
529
|
retry_config=retry_config,
|
|
530
|
+
search_field_paths=search_field_paths,
|
|
447
531
|
)
|
|
448
532
|
|
|
449
533
|
return model
|
|
@@ -1032,7 +1032,9 @@ class LocalExecutor:
|
|
|
1032
1032
|
if "variables" in graphql_config and graphql_config["variables"]:
|
|
1033
1033
|
variables = self._interpolate_variables(graphql_config["variables"], params, param_defaults)
|
|
1034
1034
|
# Filter out None values (optional fields not provided) - matches REST _extract_body() behavior
|
|
1035
|
-
|
|
1035
|
+
# But preserve None for variables explicitly marked as nullable (e.g., to unassign a user)
|
|
1036
|
+
nullable_vars = set(graphql_config.get("x-airbyte-nullable-variables") or [])
|
|
1037
|
+
body["variables"] = {k: v for k, v in variables.items() if v is not None or k in nullable_vars}
|
|
1036
1038
|
|
|
1037
1039
|
# Add operation name if specified
|
|
1038
1040
|
if "operationName" in graphql_config:
|
|
@@ -18,6 +18,185 @@ from typing import Any, Protocol
|
|
|
18
18
|
MAX_EXAMPLE_QUESTIONS = 5 # Maximum number of example questions to include in description
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
def _type_includes(type_value: Any, target: str) -> bool:
|
|
22
|
+
if isinstance(type_value, list):
|
|
23
|
+
return target in type_value
|
|
24
|
+
return type_value == target
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _is_object_schema(schema: dict[str, Any]) -> bool:
|
|
28
|
+
if "properties" in schema:
|
|
29
|
+
return True
|
|
30
|
+
return _type_includes(schema.get("type"), "object")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _is_array_schema(schema: dict[str, Any]) -> bool:
|
|
34
|
+
if "items" in schema:
|
|
35
|
+
return True
|
|
36
|
+
return _type_includes(schema.get("type"), "array")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _dedupe_param_entries(entries: list[tuple[str, bool]]) -> list[tuple[str, bool]]:
|
|
40
|
+
seen: dict[str, bool] = {}
|
|
41
|
+
ordered: list[str] = []
|
|
42
|
+
for name, required in entries:
|
|
43
|
+
if name not in seen:
|
|
44
|
+
seen[name] = required
|
|
45
|
+
ordered.append(name)
|
|
46
|
+
else:
|
|
47
|
+
seen[name] = seen[name] or required
|
|
48
|
+
return [(name, seen[name]) for name in ordered]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _flatten_schema_params(
|
|
52
|
+
schema: dict[str, Any],
|
|
53
|
+
prefix: str = "",
|
|
54
|
+
parent_required: bool = True,
|
|
55
|
+
seen_stack: set[int] | None = None,
|
|
56
|
+
) -> list[tuple[str, bool]]:
|
|
57
|
+
if not isinstance(schema, dict):
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
if seen_stack is None:
|
|
61
|
+
seen_stack = set()
|
|
62
|
+
|
|
63
|
+
schema_id = id(schema)
|
|
64
|
+
if schema_id in seen_stack:
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
seen_stack.add(schema_id)
|
|
68
|
+
try:
|
|
69
|
+
entries: list[tuple[str, bool]] = []
|
|
70
|
+
|
|
71
|
+
for subschema in schema.get("allOf", []) or []:
|
|
72
|
+
if isinstance(subschema, dict):
|
|
73
|
+
entries.extend(_flatten_schema_params(subschema, prefix, parent_required, seen_stack))
|
|
74
|
+
|
|
75
|
+
for keyword in ("anyOf", "oneOf"):
|
|
76
|
+
for subschema in schema.get(keyword, []) or []:
|
|
77
|
+
if isinstance(subschema, dict):
|
|
78
|
+
entries.extend(_flatten_schema_params(subschema, prefix, False, seen_stack))
|
|
79
|
+
|
|
80
|
+
properties = schema.get("properties")
|
|
81
|
+
if isinstance(properties, dict):
|
|
82
|
+
required_fields = set(schema.get("required", [])) if isinstance(schema.get("required"), list) else set()
|
|
83
|
+
for prop_name, prop_schema in properties.items():
|
|
84
|
+
path = f"{prefix}{prop_name}" if prefix else prop_name
|
|
85
|
+
is_required = parent_required and prop_name in required_fields
|
|
86
|
+
entries.append((path, is_required))
|
|
87
|
+
|
|
88
|
+
if isinstance(prop_schema, dict):
|
|
89
|
+
if _is_array_schema(prop_schema):
|
|
90
|
+
array_path = f"{path}[]"
|
|
91
|
+
entries.append((array_path, is_required))
|
|
92
|
+
items = prop_schema.get("items")
|
|
93
|
+
if isinstance(items, dict):
|
|
94
|
+
entries.extend(_flatten_schema_params(items, prefix=f"{array_path}.", parent_required=is_required, seen_stack=seen_stack))
|
|
95
|
+
if _is_object_schema(prop_schema):
|
|
96
|
+
entries.extend(_flatten_schema_params(prop_schema, prefix=f"{path}.", parent_required=is_required, seen_stack=seen_stack))
|
|
97
|
+
|
|
98
|
+
return _dedupe_param_entries(entries)
|
|
99
|
+
finally:
|
|
100
|
+
seen_stack.remove(schema_id)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _cache_field_value(field: Any, key: str) -> Any:
|
|
104
|
+
if isinstance(field, dict):
|
|
105
|
+
return field.get(key)
|
|
106
|
+
return getattr(field, key, None)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _flatten_cache_properties(properties: dict[str, Any], prefix: str) -> list[str]:
|
|
110
|
+
entries: list[str] = []
|
|
111
|
+
for prop_name, prop in properties.items():
|
|
112
|
+
path = f"{prefix}{prop_name}" if prefix else prop_name
|
|
113
|
+
entries.append(path)
|
|
114
|
+
|
|
115
|
+
prop_type = _cache_field_value(prop, "type")
|
|
116
|
+
prop_properties = _cache_field_value(prop, "properties")
|
|
117
|
+
|
|
118
|
+
if _type_includes(prop_type, "array"):
|
|
119
|
+
array_path = f"{path}[]"
|
|
120
|
+
entries.append(array_path)
|
|
121
|
+
if isinstance(prop_properties, dict):
|
|
122
|
+
entries.extend(_flatten_cache_properties(prop_properties, prefix=f"{array_path}."))
|
|
123
|
+
elif isinstance(prop_properties, dict):
|
|
124
|
+
entries.extend(_flatten_cache_properties(prop_properties, prefix=f"{path}."))
|
|
125
|
+
|
|
126
|
+
return entries
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _flatten_cache_field_paths(field: Any) -> list[str]:
|
|
130
|
+
field_name = _cache_field_value(field, "name")
|
|
131
|
+
if not isinstance(field_name, str) or not field_name:
|
|
132
|
+
return []
|
|
133
|
+
|
|
134
|
+
field_type = _cache_field_value(field, "type")
|
|
135
|
+
field_properties = _cache_field_value(field, "properties")
|
|
136
|
+
|
|
137
|
+
entries = [field_name]
|
|
138
|
+
if _type_includes(field_type, "array"):
|
|
139
|
+
array_path = f"{field_name}[]"
|
|
140
|
+
entries.append(array_path)
|
|
141
|
+
if isinstance(field_properties, dict):
|
|
142
|
+
entries.extend(_flatten_cache_properties(field_properties, prefix=f"{array_path}."))
|
|
143
|
+
elif isinstance(field_properties, dict):
|
|
144
|
+
entries.extend(_flatten_cache_properties(field_properties, prefix=f"{field_name}."))
|
|
145
|
+
|
|
146
|
+
return entries
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _dedupe_strings(values: list[str]) -> list[str]:
|
|
150
|
+
seen: set[str] = set()
|
|
151
|
+
ordered: list[str] = []
|
|
152
|
+
for value in values:
|
|
153
|
+
if value not in seen:
|
|
154
|
+
seen.add(value)
|
|
155
|
+
ordered.append(value)
|
|
156
|
+
return ordered
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _collect_search_field_paths(model: ConnectorModelProtocol) -> dict[str, list[str]]:
|
|
160
|
+
search_field_paths = getattr(model, "search_field_paths", None)
|
|
161
|
+
if isinstance(search_field_paths, dict) and search_field_paths:
|
|
162
|
+
normalized: dict[str, list[str]] = {}
|
|
163
|
+
for entity, fields in search_field_paths.items():
|
|
164
|
+
if not isinstance(entity, str) or not entity:
|
|
165
|
+
continue
|
|
166
|
+
if isinstance(fields, list):
|
|
167
|
+
normalized[entity] = _dedupe_strings([field for field in fields if isinstance(field, str) and field])
|
|
168
|
+
return normalized
|
|
169
|
+
|
|
170
|
+
openapi_spec = getattr(model, "openapi_spec", None)
|
|
171
|
+
info = getattr(openapi_spec, "info", None)
|
|
172
|
+
cache_config = getattr(info, "x_airbyte_cache", None)
|
|
173
|
+
entities = getattr(cache_config, "entities", None)
|
|
174
|
+
if not isinstance(entities, list):
|
|
175
|
+
return {}
|
|
176
|
+
|
|
177
|
+
search_fields: dict[str, list[str]] = {}
|
|
178
|
+
for entity in entities:
|
|
179
|
+
entity_name = _cache_field_value(entity, "entity")
|
|
180
|
+
if not isinstance(entity_name, str) or not entity_name:
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
fields = _cache_field_value(entity, "fields") or []
|
|
184
|
+
if not isinstance(fields, list):
|
|
185
|
+
continue
|
|
186
|
+
field_paths: list[str] = []
|
|
187
|
+
for field in fields:
|
|
188
|
+
field_paths.extend(_flatten_cache_field_paths(field))
|
|
189
|
+
|
|
190
|
+
search_fields[entity_name] = _dedupe_strings(field_paths)
|
|
191
|
+
|
|
192
|
+
return search_fields
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _format_search_param_signature() -> str:
|
|
196
|
+
params = ["query*", "limit?", "cursor?", "fields?"]
|
|
197
|
+
return f"({', '.join(params)})"
|
|
198
|
+
|
|
199
|
+
|
|
21
200
|
class EndpointProtocol(Protocol):
|
|
22
201
|
"""Protocol defining the expected interface for endpoint parameters.
|
|
23
202
|
|
|
@@ -54,6 +233,9 @@ class ConnectorModelProtocol(Protocol):
|
|
|
54
233
|
@property
|
|
55
234
|
def openapi_spec(self) -> Any: ...
|
|
56
235
|
|
|
236
|
+
@property
|
|
237
|
+
def search_field_paths(self) -> dict[str, list[str]] | None: ...
|
|
238
|
+
|
|
57
239
|
|
|
58
240
|
def format_param_signature(endpoint: EndpointProtocol) -> str:
|
|
59
241
|
"""Format parameter signature for an endpoint action.
|
|
@@ -86,9 +268,12 @@ def format_param_signature(endpoint: EndpointProtocol) -> str:
|
|
|
86
268
|
required = schema.get("required", False)
|
|
87
269
|
params.append(f"{name}{'*' if required else '?'}")
|
|
88
270
|
|
|
89
|
-
# Body fields
|
|
90
|
-
if request_schema:
|
|
91
|
-
|
|
271
|
+
# Body fields (include nested params from schema when available)
|
|
272
|
+
if isinstance(request_schema, dict):
|
|
273
|
+
for name, required in _flatten_schema_params(request_schema):
|
|
274
|
+
params.append(f"{name}{'*' if required else '?'}")
|
|
275
|
+
elif request_schema:
|
|
276
|
+
required_fields = set(request_schema.get("required", [])) if isinstance(request_schema, dict) else set()
|
|
92
277
|
for name in body_fields:
|
|
93
278
|
params.append(f"{name}{'*' if name in required_fields else '?'}")
|
|
94
279
|
|
|
@@ -99,7 +284,7 @@ def describe_entities(model: ConnectorModelProtocol) -> list[dict[str, Any]]:
|
|
|
99
284
|
"""Generate entity descriptions from ConnectorModel.
|
|
100
285
|
|
|
101
286
|
Returns a list of entity descriptions with detailed parameter information
|
|
102
|
-
for each action. This is used by generated connectors'
|
|
287
|
+
for each action. This is used by generated connectors' list_entities() method.
|
|
103
288
|
|
|
104
289
|
Args:
|
|
105
290
|
model: Object conforming to ConnectorModelProtocol (e.g., ConnectorModel)
|
|
@@ -203,8 +388,8 @@ def generate_tool_description(model: ConnectorModelProtocol) -> str:
|
|
|
203
388
|
- Response structure documentation with pagination hints
|
|
204
389
|
- Example questions if available in the OpenAPI spec
|
|
205
390
|
|
|
206
|
-
This is used by the Connector.
|
|
207
|
-
|
|
391
|
+
This is used by the Connector.tool_utils decorator to populate function
|
|
392
|
+
docstrings for AI framework integration.
|
|
208
393
|
|
|
209
394
|
Args:
|
|
210
395
|
model: Object conforming to ConnectorModelProtocol (e.g., ConnectorModel)
|
|
@@ -213,8 +398,11 @@ def generate_tool_description(model: ConnectorModelProtocol) -> str:
|
|
|
213
398
|
Formatted description string suitable for AI tool documentation
|
|
214
399
|
"""
|
|
215
400
|
lines = []
|
|
401
|
+
# NOTE: Do not insert blank lines in the docstring; pydantic-ai parsing truncates
|
|
402
|
+
# at the first empty line and only keeps the initial section.
|
|
216
403
|
|
|
217
404
|
# Entity/action parameter details (including pagination params like limit, starting_after)
|
|
405
|
+
search_field_paths = _collect_search_field_paths(model)
|
|
218
406
|
lines.append("ENTITIES AND PARAMETERS:")
|
|
219
407
|
for entity in model.entities:
|
|
220
408
|
lines.append(f" {entity.name}:")
|
|
@@ -228,14 +416,41 @@ def generate_tool_description(model: ConnectorModelProtocol) -> str:
|
|
|
228
416
|
lines.append(f" - {action_str}{param_sig}")
|
|
229
417
|
else:
|
|
230
418
|
lines.append(f" - {action_str}()")
|
|
419
|
+
if entity.name in search_field_paths:
|
|
420
|
+
search_sig = _format_search_param_signature()
|
|
421
|
+
lines.append(f" - search{search_sig}")
|
|
231
422
|
|
|
232
423
|
# Response structure (brief, includes pagination hint)
|
|
233
|
-
lines.append("")
|
|
234
424
|
lines.append("RESPONSE STRUCTURE:")
|
|
235
425
|
lines.append(" - list/api_search: {data: [...], meta: {has_more: bool}}")
|
|
236
426
|
lines.append(" - get: Returns entity directly (no envelope)")
|
|
237
427
|
lines.append(" To paginate: pass starting_after=<last_id> while has_more is true")
|
|
238
428
|
|
|
429
|
+
lines.append("GUIDELINES:")
|
|
430
|
+
lines.append(' - Prefer cached search over direct API calls when using execute(): action="search" whenever possible.')
|
|
431
|
+
lines.append(" - Direct API actions (list/get/download) are slower and should be used only if search cannot answer the query.")
|
|
432
|
+
lines.append(" - Keep results small: use params.fields, params.query.filter, small params.limit, and cursor pagination.")
|
|
433
|
+
lines.append(" - If output is too large, refine the query with tighter filters/fields/limit.")
|
|
434
|
+
|
|
435
|
+
if search_field_paths:
|
|
436
|
+
lines.append("SEARCH (PREFERRED):")
|
|
437
|
+
lines.append(' execute(entity, action="search", params={')
|
|
438
|
+
lines.append(' "query": {"filter": <condition>, "sort": [{"field": "asc|desc"}, ...]},')
|
|
439
|
+
lines.append(' "limit": <int>, "cursor": <str>, "fields": ["field", "nested.field", ...]')
|
|
440
|
+
lines.append(" })")
|
|
441
|
+
lines.append(' Example: {"query": {"filter": {"eq": {"title": "Intro to Airbyte | Miinto"}}}, "limit": 1,')
|
|
442
|
+
lines.append(' "fields": ["id", "title", "started", "primaryUserId"]}')
|
|
443
|
+
lines.append(" Conditions are composable:")
|
|
444
|
+
lines.append(" - eq, neq, gt, gte, lt, lte, in, like, fuzzy, keyword, contains, any")
|
|
445
|
+
lines.append(' - and/or/not to combine conditions (e.g., {"and": [cond1, cond2]})')
|
|
446
|
+
|
|
447
|
+
lines.append("SEARCHABLE FIELDS:")
|
|
448
|
+
for entity_name, field_paths in search_field_paths.items():
|
|
449
|
+
if field_paths:
|
|
450
|
+
lines.append(f" {entity_name}: {', '.join(field_paths)}")
|
|
451
|
+
else:
|
|
452
|
+
lines.append(f" {entity_name}: (no fields listed)")
|
|
453
|
+
|
|
239
454
|
# Add example questions if available in openapi_spec
|
|
240
455
|
openapi_spec = getattr(model, "openapi_spec", None)
|
|
241
456
|
if openapi_spec:
|
|
@@ -245,18 +460,15 @@ def generate_tool_description(model: ConnectorModelProtocol) -> str:
|
|
|
245
460
|
if example_questions:
|
|
246
461
|
supported = getattr(example_questions, "supported", None)
|
|
247
462
|
if supported:
|
|
248
|
-
lines.append("")
|
|
249
463
|
lines.append("EXAMPLE QUESTIONS:")
|
|
250
464
|
for q in supported[:MAX_EXAMPLE_QUESTIONS]:
|
|
251
465
|
lines.append(f" - {q}")
|
|
252
466
|
|
|
253
467
|
# Generic parameter description for function signature
|
|
254
|
-
lines.append("")
|
|
255
468
|
lines.append("FUNCTION PARAMETERS:")
|
|
256
469
|
lines.append(" - entity: Entity name (string)")
|
|
257
470
|
lines.append(" - action: Operation to perform (string)")
|
|
258
471
|
lines.append(" - params: Operation parameters (dict) - see entity details above")
|
|
259
|
-
lines.append("")
|
|
260
472
|
lines.append("Parameter markers: * = required, ? = optional")
|
|
261
473
|
|
|
262
474
|
return "\n".join(lines)
|