airbyte-agent-hubspot 0.15.23__tar.gz → 0.15.30__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_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/CHANGELOG.md +35 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/PKG-INFO +13 -9
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/README.md +12 -8
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/executor/local_executor.py +39 -19
- airbyte_agent_hubspot-0.15.30/airbyte_agent_hubspot/_vendored/connector_sdk/introspection.py +262 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/connector.py +89 -4
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/connector_model.py +1 -1
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/pyproject.toml +1 -1
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/.gitignore +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/REFERENCE.md +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/auth_strategies.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/auth_template.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/cloud_utils/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/cloud_utils/client.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/connector_model_loader.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/constants.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/exceptions.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/executor/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/executor/hosted_executor.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/executor/models.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/extensions.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/adapters/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/adapters/httpx_adapter.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/config.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/exceptions.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/protocols.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http/response.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/http_client.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/logging/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/logging/logger.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/logging/types.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/observability/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/observability/models.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/observability/redactor.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/observability/session.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/performance/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/performance/instrumentation.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/performance/metrics.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/base.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/components.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/connector.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/extensions.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/operations.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/schema/security.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/secrets.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/telemetry/__init__.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/telemetry/config.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/telemetry/events.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/telemetry/tracker.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/types.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/utils.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/_vendored/connector_sdk/validation.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/models.py +0 -0
- {airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/types.py +0 -0
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Hubspot changelog
|
|
2
2
|
|
|
3
|
+
## [0.15.30] - 2026-01-09
|
|
4
|
+
- Updated connector definition (YAML version 0.1.3)
|
|
5
|
+
- Source commit: da9b741b
|
|
6
|
+
- SDK version: 0.1.0
|
|
7
|
+
|
|
8
|
+
## [0.15.29] - 2026-01-07
|
|
9
|
+
- Updated connector definition (YAML version 0.1.3)
|
|
10
|
+
- Source commit: d023e05f
|
|
11
|
+
- SDK version: 0.1.0
|
|
12
|
+
|
|
13
|
+
## [0.15.28] - 2026-01-06
|
|
14
|
+
- Updated connector definition (YAML version 0.1.3)
|
|
15
|
+
- Source commit: 0580c727
|
|
16
|
+
- SDK version: 0.1.0
|
|
17
|
+
|
|
18
|
+
## [0.15.27] - 2026-01-06
|
|
19
|
+
- Updated connector definition (YAML version 0.1.3)
|
|
20
|
+
- Source commit: e0e2f989
|
|
21
|
+
- SDK version: 0.1.0
|
|
22
|
+
|
|
23
|
+
## [0.15.26] - 2026-01-05
|
|
24
|
+
- Updated connector definition (YAML version 0.1.3)
|
|
25
|
+
- Source commit: 3e274293
|
|
26
|
+
- SDK version: 0.1.0
|
|
27
|
+
|
|
28
|
+
## [0.15.25] - 2025-12-22
|
|
29
|
+
- Updated connector definition (YAML version 0.1.3)
|
|
30
|
+
- Source commit: 0eb1b1c4
|
|
31
|
+
- SDK version: 0.1.0
|
|
32
|
+
|
|
33
|
+
## [0.15.24] - 2025-12-19
|
|
34
|
+
- Updated connector definition (YAML version 0.1.2)
|
|
35
|
+
- Source commit: 12f6b994
|
|
36
|
+
- SDK version: 0.1.0
|
|
37
|
+
|
|
3
38
|
## [0.15.23] - 2025-12-19
|
|
4
39
|
- Updated connector definition (YAML version 0.1.2)
|
|
5
40
|
- Source commit: 5d11bfdf
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-hubspot
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.30
|
|
4
4
|
Summary: Airbyte Hubspot Connector for AI platforms
|
|
5
5
|
Project-URL: Homepage, https://github.com/airbytehq/airbyte-embedded
|
|
6
6
|
Project-URL: Documentation, https://github.com/airbytehq/airbyte-embedded/tree/main/integrations
|
|
@@ -41,10 +41,12 @@ tickets, and custom objects for customer relationship management and sales analy
|
|
|
41
41
|
|
|
42
42
|
## Example questions
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
The Hubspot connector is optimized to handle prompts like these.
|
|
45
|
+
|
|
46
|
+
- Show me all deals from \{company\} this quarter
|
|
45
47
|
- What are the top 5 most valuable deals in my pipeline right now?
|
|
46
|
-
- List recent tickets from
|
|
47
|
-
- Search for contacts in the marketing department at
|
|
48
|
+
- List recent tickets from \{customer\} and analyze their support trends
|
|
49
|
+
- Search for contacts in the marketing department at \{company\}
|
|
48
50
|
- Give me an overview of my sales team's deals in the last 30 days
|
|
49
51
|
- Identify the most active companies in our CRM this month
|
|
50
52
|
- Compare the number of deals closed by different sales representatives
|
|
@@ -52,8 +54,10 @@ tickets, and custom objects for customer relationship management and sales analy
|
|
|
52
54
|
|
|
53
55
|
## Unsupported questions
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
The Hubspot connector isn't currently able to handle prompts like these.
|
|
58
|
+
|
|
59
|
+
- Create a new contact record for \{person\}
|
|
60
|
+
- Update the contact information for \{customer\}
|
|
57
61
|
- Delete the ticket from last week's support case
|
|
58
62
|
- Schedule a follow-up task for this deal
|
|
59
63
|
- Send an email to all contacts in the sales pipeline
|
|
@@ -101,6 +105,6 @@ For the service's official API docs, see the [Hubspot API reference](https://dev
|
|
|
101
105
|
|
|
102
106
|
## Version information
|
|
103
107
|
|
|
104
|
-
- **Package version:** 0.15.
|
|
105
|
-
- **Connector version:** 0.1.
|
|
106
|
-
- **Generated with Connector SDK commit SHA:**
|
|
108
|
+
- **Package version:** 0.15.30
|
|
109
|
+
- **Connector version:** 0.1.3
|
|
110
|
+
- **Generated with Connector SDK commit SHA:** da9b741b7b9d8091113af16ba8ec5d5e5d13b749
|
|
@@ -7,10 +7,12 @@ tickets, and custom objects for customer relationship management and sales analy
|
|
|
7
7
|
|
|
8
8
|
## Example questions
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The Hubspot connector is optimized to handle prompts like these.
|
|
11
|
+
|
|
12
|
+
- Show me all deals from \{company\} this quarter
|
|
11
13
|
- What are the top 5 most valuable deals in my pipeline right now?
|
|
12
|
-
- List recent tickets from
|
|
13
|
-
- Search for contacts in the marketing department at
|
|
14
|
+
- List recent tickets from \{customer\} and analyze their support trends
|
|
15
|
+
- Search for contacts in the marketing department at \{company\}
|
|
14
16
|
- Give me an overview of my sales team's deals in the last 30 days
|
|
15
17
|
- Identify the most active companies in our CRM this month
|
|
16
18
|
- Compare the number of deals closed by different sales representatives
|
|
@@ -18,8 +20,10 @@ tickets, and custom objects for customer relationship management and sales analy
|
|
|
18
20
|
|
|
19
21
|
## Unsupported questions
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
The Hubspot connector isn't currently able to handle prompts like these.
|
|
24
|
+
|
|
25
|
+
- Create a new contact record for \{person\}
|
|
26
|
+
- Update the contact information for \{customer\}
|
|
23
27
|
- Delete the ticket from last week's support case
|
|
24
28
|
- Schedule a follow-up task for this deal
|
|
25
29
|
- Send an email to all contacts in the sales pipeline
|
|
@@ -67,6 +71,6 @@ For the service's official API docs, see the [Hubspot API reference](https://dev
|
|
|
67
71
|
|
|
68
72
|
## Version information
|
|
69
73
|
|
|
70
|
-
- **Package version:** 0.15.
|
|
71
|
-
- **Connector version:** 0.1.
|
|
72
|
-
- **Generated with Connector SDK commit SHA:**
|
|
74
|
+
- **Package version:** 0.15.30
|
|
75
|
+
- **Connector version:** 0.1.3
|
|
76
|
+
- **Generated with Connector SDK commit SHA:** da9b741b7b9d8091113af16ba8ec5d5e5d13b749
|
|
@@ -674,16 +674,16 @@ class LocalExecutor:
|
|
|
674
674
|
return {key: value for key, value in params.items() if key in allowed_params}
|
|
675
675
|
|
|
676
676
|
def _extract_body(self, allowed_fields: list[str], params: dict[str, Any]) -> dict[str, Any]:
|
|
677
|
-
"""Extract body fields from params.
|
|
677
|
+
"""Extract body fields from params, filtering out None values.
|
|
678
678
|
|
|
679
679
|
Args:
|
|
680
680
|
allowed_fields: List of allowed body field names
|
|
681
681
|
params: All parameters
|
|
682
682
|
|
|
683
683
|
Returns:
|
|
684
|
-
Dictionary of body fields
|
|
684
|
+
Dictionary of body fields with None values filtered out
|
|
685
685
|
"""
|
|
686
|
-
return {key: value for key, value in params.items() if key in allowed_fields}
|
|
686
|
+
return {key: value for key, value in params.items() if key in allowed_fields and value is not None}
|
|
687
687
|
|
|
688
688
|
def _serialize_deep_object_params(self, params: dict[str, Any], deep_object_param_names: list[str]) -> dict[str, Any]:
|
|
689
689
|
"""Serialize deepObject parameters to bracket notation format.
|
|
@@ -837,7 +837,9 @@ class LocalExecutor:
|
|
|
837
837
|
Request body dict or None if no body needed
|
|
838
838
|
"""
|
|
839
839
|
if endpoint.graphql_body:
|
|
840
|
-
|
|
840
|
+
# Extract defaults from query_params_schema for GraphQL variable interpolation
|
|
841
|
+
param_defaults = {name: schema.get("default") for name, schema in endpoint.query_params_schema.items() if "default" in schema}
|
|
842
|
+
return self._build_graphql_body(endpoint.graphql_body, params, param_defaults)
|
|
841
843
|
elif endpoint.body_fields:
|
|
842
844
|
return self._extract_body(endpoint.body_fields, params)
|
|
843
845
|
return None
|
|
@@ -903,12 +905,18 @@ class LocalExecutor:
|
|
|
903
905
|
|
|
904
906
|
return query
|
|
905
907
|
|
|
906
|
-
def _build_graphql_body(
|
|
908
|
+
def _build_graphql_body(
|
|
909
|
+
self,
|
|
910
|
+
graphql_config: dict[str, Any],
|
|
911
|
+
params: dict[str, Any],
|
|
912
|
+
param_defaults: dict[str, Any] | None = None,
|
|
913
|
+
) -> dict[str, Any]:
|
|
907
914
|
"""Build GraphQL request body with variable substitution and field selection.
|
|
908
915
|
|
|
909
916
|
Args:
|
|
910
917
|
graphql_config: GraphQL configuration from x-airbyte-body-type extension
|
|
911
918
|
params: Parameters from execute() call
|
|
919
|
+
param_defaults: Default values for params from query_params_schema
|
|
912
920
|
|
|
913
921
|
Returns:
|
|
914
922
|
GraphQL request body: {"query": "...", "variables": {...}}
|
|
@@ -922,7 +930,7 @@ class LocalExecutor:
|
|
|
922
930
|
|
|
923
931
|
# Substitute variables from params
|
|
924
932
|
if "variables" in graphql_config and graphql_config["variables"]:
|
|
925
|
-
body["variables"] = self._interpolate_variables(graphql_config["variables"], params)
|
|
933
|
+
body["variables"] = self._interpolate_variables(graphql_config["variables"], params, param_defaults)
|
|
926
934
|
|
|
927
935
|
# Add operation name if specified
|
|
928
936
|
if "operationName" in graphql_config:
|
|
@@ -981,7 +989,12 @@ class LocalExecutor:
|
|
|
981
989
|
fields_str = " ".join(graphql_fields)
|
|
982
990
|
return query.replace("{{ fields }}", fields_str)
|
|
983
991
|
|
|
984
|
-
def _interpolate_variables(
|
|
992
|
+
def _interpolate_variables(
|
|
993
|
+
self,
|
|
994
|
+
variables: dict[str, Any],
|
|
995
|
+
params: dict[str, Any],
|
|
996
|
+
param_defaults: dict[str, Any] | None = None,
|
|
997
|
+
) -> dict[str, Any]:
|
|
985
998
|
"""Recursively interpolate variables using params.
|
|
986
999
|
|
|
987
1000
|
Preserves types (doesn't stringify everything).
|
|
@@ -990,15 +1003,18 @@ class LocalExecutor:
|
|
|
990
1003
|
- Direct replacement: "{{ owner }}" → params["owner"] (preserves type)
|
|
991
1004
|
- Nested objects: {"input": {"name": "{{ name }}"}}
|
|
992
1005
|
- Arrays: [{"id": "{{ id }}"}]
|
|
993
|
-
-
|
|
1006
|
+
- Default values: "{{ per_page }}" → param_defaults["per_page"] if not in params
|
|
1007
|
+
- Unsubstituted placeholders: "{{ states }}" → None (for optional params without defaults)
|
|
994
1008
|
|
|
995
1009
|
Args:
|
|
996
1010
|
variables: Variables dict with template placeholders
|
|
997
1011
|
params: Parameters to substitute
|
|
1012
|
+
param_defaults: Default values for params from query_params_schema
|
|
998
1013
|
|
|
999
1014
|
Returns:
|
|
1000
1015
|
Interpolated variables dict with types preserved
|
|
1001
1016
|
"""
|
|
1017
|
+
defaults = param_defaults or {}
|
|
1002
1018
|
|
|
1003
1019
|
def interpolate_value(value: Any) -> Any:
|
|
1004
1020
|
if isinstance(value, str):
|
|
@@ -1012,8 +1028,15 @@ class LocalExecutor:
|
|
|
1012
1028
|
value = value.replace(placeholder, str(param_value))
|
|
1013
1029
|
|
|
1014
1030
|
# Check if any unsubstituted placeholders remain
|
|
1015
|
-
# If so, return None (treats as "not provided" for optional params)
|
|
1016
1031
|
if re.search(r"\{\{\s*\w+\s*\}\}", value):
|
|
1032
|
+
# Extract placeholder name and check for default value
|
|
1033
|
+
match = re.search(r"\{\{\s*(\w+)\s*\}\}", value)
|
|
1034
|
+
if match:
|
|
1035
|
+
param_name = match.group(1)
|
|
1036
|
+
if param_name in defaults:
|
|
1037
|
+
# Use default value (preserves type)
|
|
1038
|
+
return defaults[param_name]
|
|
1039
|
+
# No default found - return None (for optional params)
|
|
1017
1040
|
return None
|
|
1018
1041
|
|
|
1019
1042
|
return value
|
|
@@ -1151,21 +1174,18 @@ class LocalExecutor:
|
|
|
1151
1174
|
if action not in (Action.CREATE, Action.UPDATE):
|
|
1152
1175
|
return
|
|
1153
1176
|
|
|
1154
|
-
#
|
|
1155
|
-
|
|
1177
|
+
# Get the request schema to find truly required fields
|
|
1178
|
+
request_schema = endpoint.request_schema
|
|
1179
|
+
if not request_schema:
|
|
1156
1180
|
return
|
|
1157
1181
|
|
|
1158
|
-
#
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
missing_fields = []
|
|
1162
|
-
for field in endpoint.body_fields:
|
|
1163
|
-
if field not in params:
|
|
1164
|
-
missing_fields.append(field)
|
|
1182
|
+
# Only validate fields explicitly marked as required in the schema
|
|
1183
|
+
required_fields = request_schema.get("required", [])
|
|
1184
|
+
missing_fields = [field for field in required_fields if field not in params]
|
|
1165
1185
|
|
|
1166
1186
|
if missing_fields:
|
|
1167
1187
|
raise MissingParameterError(
|
|
1168
|
-
f"Missing required body fields for {entity}.{action.value}: {missing_fields}. Provided parameters: {list(params.keys())}"
|
|
1188
|
+
f"Missing required body fields for {entity}.{action.value}: {missing_fields}. " f"Provided parameters: {list(params.keys())}"
|
|
1169
1189
|
)
|
|
1170
1190
|
|
|
1171
1191
|
async def close(self):
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared introspection utilities for connector metadata.
|
|
3
|
+
|
|
4
|
+
This module provides utilities for introspecting connector metadata,
|
|
5
|
+
generating descriptions, and formatting parameter signatures. These
|
|
6
|
+
functions are used by both the runtime decorators and the generated
|
|
7
|
+
connector code.
|
|
8
|
+
|
|
9
|
+
The module is designed to work with any object conforming to the
|
|
10
|
+
ConnectorModel and EndpointDefinition interfaces from connector_sdk.types.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Protocol
|
|
16
|
+
|
|
17
|
+
# Constants
|
|
18
|
+
MAX_EXAMPLE_QUESTIONS = 5 # Maximum number of example questions to include in description
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EndpointProtocol(Protocol):
|
|
22
|
+
"""Protocol defining the expected interface for endpoint parameters.
|
|
23
|
+
|
|
24
|
+
This allows functions to work with any endpoint-like object
|
|
25
|
+
that has these attributes, including EndpointDefinition and mock objects.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
path_params: list[str]
|
|
29
|
+
path_params_schema: dict[str, dict[str, Any]]
|
|
30
|
+
query_params: list[str]
|
|
31
|
+
query_params_schema: dict[str, dict[str, Any]]
|
|
32
|
+
body_fields: list[str]
|
|
33
|
+
request_schema: dict[str, Any] | None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class EntityProtocol(Protocol):
|
|
37
|
+
"""Protocol defining the expected interface for entity definitions."""
|
|
38
|
+
|
|
39
|
+
name: str
|
|
40
|
+
actions: list[Any]
|
|
41
|
+
endpoints: dict[Any, EndpointProtocol]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ConnectorModelProtocol(Protocol):
|
|
45
|
+
"""Protocol defining the expected interface for connector model parameters.
|
|
46
|
+
|
|
47
|
+
This allows functions to work with any connector-like object
|
|
48
|
+
that has these attributes, including ConnectorModel and mock objects.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def entities(self) -> list[EntityProtocol]: ...
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def openapi_spec(self) -> Any: ...
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def format_param_signature(endpoint: EndpointProtocol) -> str:
|
|
59
|
+
"""Format parameter signature for an endpoint action.
|
|
60
|
+
|
|
61
|
+
Returns a string like: (id*) or (limit?, starting_after?, email?)
|
|
62
|
+
where * = required, ? = optional
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
endpoint: Object conforming to EndpointProtocol (e.g., EndpointDefinition)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Formatted parameter signature string
|
|
69
|
+
"""
|
|
70
|
+
params = []
|
|
71
|
+
|
|
72
|
+
# Defensive: safely access attributes with defaults for malformed endpoints
|
|
73
|
+
path_params = getattr(endpoint, "path_params", []) or []
|
|
74
|
+
query_params = getattr(endpoint, "query_params", []) or []
|
|
75
|
+
query_params_schema = getattr(endpoint, "query_params_schema", {}) or {}
|
|
76
|
+
body_fields = getattr(endpoint, "body_fields", []) or []
|
|
77
|
+
request_schema = getattr(endpoint, "request_schema", None)
|
|
78
|
+
|
|
79
|
+
# Path params (always required)
|
|
80
|
+
for name in path_params:
|
|
81
|
+
params.append(f"{name}*")
|
|
82
|
+
|
|
83
|
+
# Query params
|
|
84
|
+
for name in query_params:
|
|
85
|
+
schema = query_params_schema.get(name, {})
|
|
86
|
+
required = schema.get("required", False)
|
|
87
|
+
params.append(f"{name}{'*' if required else '?'}")
|
|
88
|
+
|
|
89
|
+
# Body fields
|
|
90
|
+
if request_schema:
|
|
91
|
+
required_fields = set(request_schema.get("required", []))
|
|
92
|
+
for name in body_fields:
|
|
93
|
+
params.append(f"{name}{'*' if name in required_fields else '?'}")
|
|
94
|
+
|
|
95
|
+
return f"({', '.join(params)})" if params else "()"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def describe_entities(model: ConnectorModelProtocol) -> list[dict[str, Any]]:
|
|
99
|
+
"""Generate entity descriptions from ConnectorModel.
|
|
100
|
+
|
|
101
|
+
Returns a list of entity descriptions with detailed parameter information
|
|
102
|
+
for each action. This is used by generated connectors' describe() method.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
model: Object conforming to ConnectorModelProtocol (e.g., ConnectorModel)
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
List of entity description dicts with keys:
|
|
109
|
+
- entity_name: Name of the entity (e.g., "contacts", "deals")
|
|
110
|
+
- description: Entity description from the first endpoint
|
|
111
|
+
- available_actions: List of actions (e.g., ["list", "get", "create"])
|
|
112
|
+
- parameters: Dict mapping action -> list of parameter dicts
|
|
113
|
+
"""
|
|
114
|
+
entities = []
|
|
115
|
+
for entity_def in model.entities:
|
|
116
|
+
description = ""
|
|
117
|
+
parameters: dict[str, list[dict[str, Any]]] = {}
|
|
118
|
+
|
|
119
|
+
endpoints = getattr(entity_def, "endpoints", {}) or {}
|
|
120
|
+
if endpoints:
|
|
121
|
+
for action, endpoint in endpoints.items():
|
|
122
|
+
# Get description from first endpoint that has one
|
|
123
|
+
if not description:
|
|
124
|
+
endpoint_desc = getattr(endpoint, "description", None)
|
|
125
|
+
if endpoint_desc:
|
|
126
|
+
description = endpoint_desc
|
|
127
|
+
|
|
128
|
+
action_params: list[dict[str, Any]] = []
|
|
129
|
+
|
|
130
|
+
# Defensive: safely access endpoint attributes
|
|
131
|
+
path_params = getattr(endpoint, "path_params", []) or []
|
|
132
|
+
path_params_schema = getattr(endpoint, "path_params_schema", {}) or {}
|
|
133
|
+
query_params = getattr(endpoint, "query_params", []) or []
|
|
134
|
+
query_params_schema = getattr(endpoint, "query_params_schema", {}) or {}
|
|
135
|
+
body_fields = getattr(endpoint, "body_fields", []) or []
|
|
136
|
+
request_schema = getattr(endpoint, "request_schema", None)
|
|
137
|
+
|
|
138
|
+
# Path params (always required)
|
|
139
|
+
for param_name in path_params:
|
|
140
|
+
schema = path_params_schema.get(param_name, {})
|
|
141
|
+
action_params.append(
|
|
142
|
+
{
|
|
143
|
+
"name": param_name,
|
|
144
|
+
"in": "path",
|
|
145
|
+
"required": True,
|
|
146
|
+
"type": schema.get("type", "string"),
|
|
147
|
+
"description": schema.get("description", ""),
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Query params
|
|
152
|
+
for param_name in query_params:
|
|
153
|
+
schema = query_params_schema.get(param_name, {})
|
|
154
|
+
action_params.append(
|
|
155
|
+
{
|
|
156
|
+
"name": param_name,
|
|
157
|
+
"in": "query",
|
|
158
|
+
"required": schema.get("required", False),
|
|
159
|
+
"type": schema.get("type", "string"),
|
|
160
|
+
"description": schema.get("description", ""),
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Body fields
|
|
165
|
+
if request_schema:
|
|
166
|
+
required_fields = request_schema.get("required", [])
|
|
167
|
+
properties = request_schema.get("properties", {})
|
|
168
|
+
for param_name in body_fields:
|
|
169
|
+
prop = properties.get(param_name, {})
|
|
170
|
+
action_params.append(
|
|
171
|
+
{
|
|
172
|
+
"name": param_name,
|
|
173
|
+
"in": "body",
|
|
174
|
+
"required": param_name in required_fields,
|
|
175
|
+
"type": prop.get("type", "string"),
|
|
176
|
+
"description": prop.get("description", ""),
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
if action_params:
|
|
181
|
+
# Action is an enum, use .value to get string
|
|
182
|
+
action_key = action.value if hasattr(action, "value") else str(action)
|
|
183
|
+
parameters[action_key] = action_params
|
|
184
|
+
|
|
185
|
+
actions = getattr(entity_def, "actions", []) or []
|
|
186
|
+
entities.append(
|
|
187
|
+
{
|
|
188
|
+
"entity_name": entity_def.name,
|
|
189
|
+
"description": description,
|
|
190
|
+
"available_actions": [a.value if hasattr(a, "value") else str(a) for a in actions],
|
|
191
|
+
"parameters": parameters,
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return entities
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def generate_tool_description(model: ConnectorModelProtocol) -> str:
|
|
199
|
+
"""Generate AI tool description from connector metadata.
|
|
200
|
+
|
|
201
|
+
Produces a detailed description that includes:
|
|
202
|
+
- Per-entity/action parameter signatures with required (*) and optional (?) markers
|
|
203
|
+
- Response structure documentation with pagination hints
|
|
204
|
+
- Example questions if available in the OpenAPI spec
|
|
205
|
+
|
|
206
|
+
This is used by the Connector.describe class method decorator to populate
|
|
207
|
+
function docstrings for AI framework integration.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
model: Object conforming to ConnectorModelProtocol (e.g., ConnectorModel)
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Formatted description string suitable for AI tool documentation
|
|
214
|
+
"""
|
|
215
|
+
lines = []
|
|
216
|
+
|
|
217
|
+
# Entity/action parameter details (including pagination params like limit, starting_after)
|
|
218
|
+
lines.append("ENTITIES AND PARAMETERS:")
|
|
219
|
+
for entity in model.entities:
|
|
220
|
+
lines.append(f" {entity.name}:")
|
|
221
|
+
actions = getattr(entity, "actions", []) or []
|
|
222
|
+
endpoints = getattr(entity, "endpoints", {}) or {}
|
|
223
|
+
for action in actions:
|
|
224
|
+
action_str = action.value if hasattr(action, "value") else str(action)
|
|
225
|
+
endpoint = endpoints.get(action)
|
|
226
|
+
if endpoint:
|
|
227
|
+
param_sig = format_param_signature(endpoint)
|
|
228
|
+
lines.append(f" - {action_str}{param_sig}")
|
|
229
|
+
else:
|
|
230
|
+
lines.append(f" - {action_str}()")
|
|
231
|
+
|
|
232
|
+
# Response structure (brief, includes pagination hint)
|
|
233
|
+
lines.append("")
|
|
234
|
+
lines.append("RESPONSE STRUCTURE:")
|
|
235
|
+
lines.append(" - list/search: {data: [...], meta: {has_more: bool}}")
|
|
236
|
+
lines.append(" - get: Returns entity directly (no envelope)")
|
|
237
|
+
lines.append(" To paginate: pass starting_after=<last_id> while has_more is true")
|
|
238
|
+
|
|
239
|
+
# Add example questions if available in openapi_spec
|
|
240
|
+
openapi_spec = getattr(model, "openapi_spec", None)
|
|
241
|
+
if openapi_spec:
|
|
242
|
+
info = getattr(openapi_spec, "info", None)
|
|
243
|
+
if info:
|
|
244
|
+
example_questions = getattr(info, "x_airbyte_example_questions", None)
|
|
245
|
+
if example_questions:
|
|
246
|
+
supported = getattr(example_questions, "supported", None)
|
|
247
|
+
if supported:
|
|
248
|
+
lines.append("")
|
|
249
|
+
lines.append("EXAMPLE QUESTIONS:")
|
|
250
|
+
for q in supported[:MAX_EXAMPLE_QUESTIONS]:
|
|
251
|
+
lines.append(f" - {q}")
|
|
252
|
+
|
|
253
|
+
# Generic parameter description for function signature
|
|
254
|
+
lines.append("")
|
|
255
|
+
lines.append("FUNCTION PARAMETERS:")
|
|
256
|
+
lines.append(" - entity: Entity name (string)")
|
|
257
|
+
lines.append(" - action: Operation to perform (string)")
|
|
258
|
+
lines.append(" - params: Operation parameters (dict) - see entity details above")
|
|
259
|
+
lines.append("")
|
|
260
|
+
lines.append("Parameter markers: * = required, ? = optional")
|
|
261
|
+
|
|
262
|
+
return "\n".join(lines)
|
{airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/connector.py
RENAMED
|
@@ -4,14 +4,15 @@ hubspot connector.
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import logging
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, TypeVar, overload
|
|
8
9
|
try:
|
|
9
10
|
from typing import Literal
|
|
10
11
|
except ImportError:
|
|
11
12
|
from typing_extensions import Literal
|
|
12
13
|
|
|
13
14
|
from .connector_model import HubspotConnectorModel
|
|
14
|
-
|
|
15
|
+
from ._vendored.connector_sdk.introspection import describe_entities, generate_tool_description
|
|
15
16
|
from .types import (
|
|
16
17
|
CompaniesGetParams,
|
|
17
18
|
CompaniesListParams,
|
|
@@ -38,7 +39,6 @@ from .types import (
|
|
|
38
39
|
TicketsSearchParamsFiltergroupsItem,
|
|
39
40
|
TicketsSearchParamsSortsItem,
|
|
40
41
|
)
|
|
41
|
-
|
|
42
42
|
if TYPE_CHECKING:
|
|
43
43
|
from .models import HubspotAuthConfig
|
|
44
44
|
# Import response models and envelope models at runtime
|
|
@@ -63,6 +63,9 @@ from .models import (
|
|
|
63
63
|
Ticket,
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
+
# TypeVar for decorator type preservation
|
|
67
|
+
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
68
|
+
|
|
66
69
|
|
|
67
70
|
class HubspotConnector:
|
|
68
71
|
"""
|
|
@@ -72,7 +75,7 @@ class HubspotConnector:
|
|
|
72
75
|
"""
|
|
73
76
|
|
|
74
77
|
connector_name = "hubspot"
|
|
75
|
-
connector_version = "0.1.
|
|
78
|
+
connector_version = "0.1.3"
|
|
76
79
|
vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
|
|
77
80
|
|
|
78
81
|
# Map of (entity, action) -> has_extractors for envelope wrapping decision
|
|
@@ -402,6 +405,88 @@ class HubspotConnector:
|
|
|
402
405
|
# No extractors - return raw response data
|
|
403
406
|
return result.data
|
|
404
407
|
|
|
408
|
+
# ===== INTROSPECTION METHODS =====
|
|
409
|
+
|
|
410
|
+
@classmethod
|
|
411
|
+
def describe(cls, func: _F) -> _F:
|
|
412
|
+
"""
|
|
413
|
+
Decorator that populates a function's docstring with connector capabilities.
|
|
414
|
+
|
|
415
|
+
This class method can be used as a decorator to automatically generate
|
|
416
|
+
comprehensive documentation for AI tool functions.
|
|
417
|
+
|
|
418
|
+
Usage:
|
|
419
|
+
@mcp.tool()
|
|
420
|
+
@HubspotConnector.describe
|
|
421
|
+
async def execute(entity: str, action: str, params: dict):
|
|
422
|
+
'''Execute operations.'''
|
|
423
|
+
...
|
|
424
|
+
|
|
425
|
+
The decorated function's __doc__ will be updated with:
|
|
426
|
+
- Available entities and their actions
|
|
427
|
+
- Parameter signatures with required (*) and optional (?) markers
|
|
428
|
+
- Response structure documentation
|
|
429
|
+
- Example questions (if available in OpenAPI spec)
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
func: The function to decorate
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
The same function with updated __doc__
|
|
436
|
+
"""
|
|
437
|
+
description = generate_tool_description(HubspotConnectorModel)
|
|
438
|
+
|
|
439
|
+
original_doc = func.__doc__ or ""
|
|
440
|
+
if original_doc.strip():
|
|
441
|
+
func.__doc__ = f"{original_doc.strip()}\n\n{description}"
|
|
442
|
+
else:
|
|
443
|
+
func.__doc__ = description
|
|
444
|
+
|
|
445
|
+
return func
|
|
446
|
+
|
|
447
|
+
def list_entities(self) -> list[dict[str, Any]]:
|
|
448
|
+
"""
|
|
449
|
+
Get structured data about available entities, actions, and parameters.
|
|
450
|
+
|
|
451
|
+
Returns a list of entity descriptions with:
|
|
452
|
+
- entity_name: Name of the entity (e.g., "contacts", "deals")
|
|
453
|
+
- description: Entity description from the first endpoint
|
|
454
|
+
- available_actions: List of actions (e.g., ["list", "get", "create"])
|
|
455
|
+
- parameters: Dict mapping action -> list of parameter dicts
|
|
456
|
+
|
|
457
|
+
Example:
|
|
458
|
+
entities = connector.list_entities()
|
|
459
|
+
for entity in entities:
|
|
460
|
+
print(f"{entity['entity_name']}: {entity['available_actions']}")
|
|
461
|
+
"""
|
|
462
|
+
return describe_entities(HubspotConnectorModel)
|
|
463
|
+
|
|
464
|
+
def entity_schema(self, entity: str) -> dict[str, Any] | None:
|
|
465
|
+
"""
|
|
466
|
+
Get the JSON schema for an entity.
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
entity: Entity name (e.g., "contacts", "companies")
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
JSON schema dict describing the entity structure, or None if not found.
|
|
473
|
+
|
|
474
|
+
Example:
|
|
475
|
+
schema = connector.entity_schema("contacts")
|
|
476
|
+
if schema:
|
|
477
|
+
print(f"Contact properties: {list(schema.get('properties', {}).keys())}")
|
|
478
|
+
"""
|
|
479
|
+
entity_def = next(
|
|
480
|
+
(e for e in HubspotConnectorModel.entities if e.name == entity),
|
|
481
|
+
None
|
|
482
|
+
)
|
|
483
|
+
if entity_def is None:
|
|
484
|
+
logging.getLogger(__name__).warning(
|
|
485
|
+
f"Entity '{entity}' not found. Available entities: "
|
|
486
|
+
f"{[e.name for e in HubspotConnectorModel.entities]}"
|
|
487
|
+
)
|
|
488
|
+
return entity_def.entity_schema if entity_def else None
|
|
489
|
+
|
|
405
490
|
|
|
406
491
|
|
|
407
492
|
class ContactsQuery:
|
|
@@ -26,7 +26,7 @@ from uuid import (
|
|
|
26
26
|
HubspotConnectorModel: ConnectorModel = ConnectorModel(
|
|
27
27
|
id=UUID('36c891d9-4bd9-43ac-bad2-10e12756272c'),
|
|
28
28
|
name='hubspot',
|
|
29
|
-
version='0.1.
|
|
29
|
+
version='0.1.3',
|
|
30
30
|
base_url='https://api.hubapi.com',
|
|
31
31
|
auth=AuthConfig(
|
|
32
32
|
type=AuthType.OAUTH2,
|
|
File without changes
|
|
File without changes
|
{airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/__init__.py
RENAMED
|
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
|
{airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/models.py
RENAMED
|
File without changes
|
{airbyte_agent_hubspot-0.15.23 → airbyte_agent_hubspot-0.15.30}/airbyte_agent_hubspot/types.py
RENAMED
|
File without changes
|