airbyte-agent-zendesk-chat 0.1.8__py3-none-any.whl → 0.1.11__py3-none-any.whl
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_chat/__init__.py +4 -4
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/connector_model_loader.py +84 -0
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/local_executor.py +3 -1
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/introspection.py +222 -10
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/base.py +34 -2
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/components.py +5 -0
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/extensions.py +71 -0
- airbyte_agent_zendesk_chat/_vendored/connector_sdk/types.py +1 -0
- airbyte_agent_zendesk_chat/connector.py +94 -32
- airbyte_agent_zendesk_chat/connector_model.py +43 -1
- airbyte_agent_zendesk_chat/models.py +31 -31
- {airbyte_agent_zendesk_chat-0.1.8.dist-info → airbyte_agent_zendesk_chat-0.1.11.dist-info}/METADATA +10 -6
- {airbyte_agent_zendesk_chat-0.1.8.dist-info → airbyte_agent_zendesk_chat-0.1.11.dist-info}/RECORD +14 -14
- {airbyte_agent_zendesk_chat-0.1.8.dist-info → airbyte_agent_zendesk_chat-0.1.11.dist-info}/WHEEL +0 -0
|
@@ -14,10 +14,10 @@ from .models import (
|
|
|
14
14
|
AgentRoles,
|
|
15
15
|
AgentTimeline,
|
|
16
16
|
Ban,
|
|
17
|
-
ChatEngagement,
|
|
18
17
|
WebpathItem,
|
|
19
|
-
ChatConversion,
|
|
20
18
|
ChatHistoryItem,
|
|
19
|
+
ChatConversion,
|
|
20
|
+
ChatEngagement,
|
|
21
21
|
Chat,
|
|
22
22
|
Visitor,
|
|
23
23
|
ChatSession,
|
|
@@ -109,10 +109,10 @@ __all__ = [
|
|
|
109
109
|
"AgentRoles",
|
|
110
110
|
"AgentTimeline",
|
|
111
111
|
"Ban",
|
|
112
|
-
"ChatEngagement",
|
|
113
112
|
"WebpathItem",
|
|
114
|
-
"ChatConversion",
|
|
115
113
|
"ChatHistoryItem",
|
|
114
|
+
"ChatConversion",
|
|
115
|
+
"ChatEngagement",
|
|
116
116
|
"Chat",
|
|
117
117
|
"Visitor",
|
|
118
118
|
"ChatSession",
|
|
@@ -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)
|
|
@@ -13,7 +13,7 @@ from uuid import UUID
|
|
|
13
13
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
14
14
|
from pydantic_core import Url
|
|
15
15
|
|
|
16
|
-
from .extensions import CacheConfig, RetryConfig
|
|
16
|
+
from .extensions import CacheConfig, ReplicationConfig, RetryConfig
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class ExampleQuestions(BaseModel):
|
|
@@ -106,6 +106,7 @@ class Info(BaseModel):
|
|
|
106
106
|
- x-airbyte-retry-config: Retry configuration for transient errors (Airbyte extension)
|
|
107
107
|
- x-airbyte-example-questions: Example questions for AI connector README (Airbyte extension)
|
|
108
108
|
- x-airbyte-cache: Cache configuration for field mapping between API and cache schemas (Airbyte extension)
|
|
109
|
+
- x-airbyte-replication-config: Replication configuration for MULTI mode connectors (Airbyte extension)
|
|
109
110
|
"""
|
|
110
111
|
|
|
111
112
|
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
@@ -124,6 +125,7 @@ class Info(BaseModel):
|
|
|
124
125
|
x_airbyte_retry_config: RetryConfig | None = Field(None, alias="x-airbyte-retry-config")
|
|
125
126
|
x_airbyte_example_questions: ExampleQuestions | None = Field(None, alias="x-airbyte-example-questions")
|
|
126
127
|
x_airbyte_cache: CacheConfig | None = Field(None, alias="x-airbyte-cache")
|
|
128
|
+
x_airbyte_replication_config: ReplicationConfig | None = Field(None, alias="x-airbyte-replication-config")
|
|
127
129
|
|
|
128
130
|
|
|
129
131
|
class ServerVariable(BaseModel):
|
|
@@ -140,6 +142,33 @@ class ServerVariable(BaseModel):
|
|
|
140
142
|
description: str | None = None
|
|
141
143
|
|
|
142
144
|
|
|
145
|
+
class EnvironmentMappingTransform(BaseModel):
|
|
146
|
+
"""
|
|
147
|
+
Structured transform for environment mapping values.
|
|
148
|
+
|
|
149
|
+
Allows transforming environment values before storing in source_config.
|
|
150
|
+
|
|
151
|
+
Example:
|
|
152
|
+
source: subdomain
|
|
153
|
+
format: "{value}.atlassian.net"
|
|
154
|
+
|
|
155
|
+
The format string uses {value} as a placeholder for the source value.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
159
|
+
|
|
160
|
+
source: str = Field(description="The environment config key to read the value from")
|
|
161
|
+
format: str | None = Field(
|
|
162
|
+
default=None,
|
|
163
|
+
description="Optional format string to transform the value. Use {value} as placeholder.",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Type alias for environment mapping values: either a simple string (config key)
|
|
168
|
+
# or a structured transform with source and optional transform template
|
|
169
|
+
EnvironmentMappingValue = str | EnvironmentMappingTransform
|
|
170
|
+
|
|
171
|
+
|
|
143
172
|
class Server(BaseModel):
|
|
144
173
|
"""
|
|
145
174
|
Server URL and variable definitions.
|
|
@@ -152,7 +181,10 @@ class Server(BaseModel):
|
|
|
152
181
|
url: str
|
|
153
182
|
description: str | None = None
|
|
154
183
|
variables: Dict[str, ServerVariable] = Field(default_factory=dict)
|
|
155
|
-
x_airbyte_replication_environment_mapping: Dict[str,
|
|
184
|
+
x_airbyte_replication_environment_mapping: Dict[str, EnvironmentMappingValue] | None = Field(
|
|
185
|
+
default=None,
|
|
186
|
+
alias="x-airbyte-replication-environment-mapping",
|
|
187
|
+
)
|
|
156
188
|
x_airbyte_replication_environment_constants: Dict[str, Any] | None = Field(
|
|
157
189
|
default=None,
|
|
158
190
|
alias="x-airbyte-replication-environment-constants",
|
|
@@ -134,6 +134,11 @@ class GraphQLBodyConfig(BaseModel):
|
|
|
134
134
|
None,
|
|
135
135
|
description="Default fields to select if not provided in request parameters. Can be a string or array of field names.",
|
|
136
136
|
)
|
|
137
|
+
nullable_variables: List[str] | None = Field(
|
|
138
|
+
default=None,
|
|
139
|
+
alias="x-airbyte-nullable-variables",
|
|
140
|
+
description="Variable names that can be explicitly set to null (e.g., to unassign a user)",
|
|
141
|
+
)
|
|
137
142
|
|
|
138
143
|
|
|
139
144
|
# Union type for all body type configs (extensible for future types like XML, SOAP, etc.)
|
|
@@ -182,6 +182,77 @@ class CacheEntityConfig(BaseModel):
|
|
|
182
182
|
return self.x_airbyte_name or self.entity
|
|
183
183
|
|
|
184
184
|
|
|
185
|
+
class ReplicationConfigProperty(BaseModel):
|
|
186
|
+
"""
|
|
187
|
+
Property definition for replication configuration fields.
|
|
188
|
+
|
|
189
|
+
Defines a single field in the replication configuration with its type,
|
|
190
|
+
description, and optional default value.
|
|
191
|
+
|
|
192
|
+
Example YAML usage:
|
|
193
|
+
x-airbyte-replication-config:
|
|
194
|
+
properties:
|
|
195
|
+
start_date:
|
|
196
|
+
type: string
|
|
197
|
+
title: Start Date
|
|
198
|
+
description: UTC date and time from which to replicate data
|
|
199
|
+
format: date-time
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
203
|
+
|
|
204
|
+
type: str
|
|
205
|
+
title: str | None = None
|
|
206
|
+
description: str | None = None
|
|
207
|
+
format: str | None = None
|
|
208
|
+
default: str | int | float | bool | None = None
|
|
209
|
+
enum: list[str] | None = None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ReplicationConfig(BaseModel):
|
|
213
|
+
"""
|
|
214
|
+
Replication configuration extension (x-airbyte-replication-config).
|
|
215
|
+
|
|
216
|
+
Defines replication-specific settings for MULTI mode connectors that need
|
|
217
|
+
to configure the underlying replication connector. This allows users who
|
|
218
|
+
use the direct-style API (credentials + environment) to also specify
|
|
219
|
+
replication settings like start_date, lookback_window, etc.
|
|
220
|
+
|
|
221
|
+
This extension is added to the Info model and provides field definitions
|
|
222
|
+
for replication configuration that gets merged into the source config
|
|
223
|
+
when creating sources.
|
|
224
|
+
|
|
225
|
+
Example YAML usage:
|
|
226
|
+
info:
|
|
227
|
+
title: HubSpot API
|
|
228
|
+
x-airbyte-replication-config:
|
|
229
|
+
title: Replication Configuration
|
|
230
|
+
description: Settings for data replication
|
|
231
|
+
properties:
|
|
232
|
+
start_date:
|
|
233
|
+
type: string
|
|
234
|
+
title: Start Date
|
|
235
|
+
description: UTC date and time from which to replicate data
|
|
236
|
+
format: date-time
|
|
237
|
+
required:
|
|
238
|
+
- start_date
|
|
239
|
+
replication_config_key_mapping:
|
|
240
|
+
start_date: start_date
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
244
|
+
|
|
245
|
+
title: str | None = None
|
|
246
|
+
description: str | None = None
|
|
247
|
+
properties: dict[str, ReplicationConfigProperty] = Field(default_factory=dict)
|
|
248
|
+
required: list[str] = Field(default_factory=list)
|
|
249
|
+
replication_config_key_mapping: dict[str, str] = Field(
|
|
250
|
+
default_factory=dict,
|
|
251
|
+
alias="replication_config_key_mapping",
|
|
252
|
+
description="Mapping from replication_config field names to source_config field names",
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
185
256
|
class CacheConfig(BaseModel):
|
|
186
257
|
"""
|
|
187
258
|
Cache configuration extension (x-airbyte-cache).
|
|
@@ -252,3 +252,4 @@ class ConnectorModel(BaseModel):
|
|
|
252
252
|
entities: list[EntityDefinition]
|
|
253
253
|
openapi_spec: Any | None = None # Optional reference to OpenAPIConnector
|
|
254
254
|
retry_config: RetryConfig | None = None # Optional retry configuration
|
|
255
|
+
search_field_paths: dict[str, list[str]] | None = None
|
|
@@ -4,8 +4,11 @@ Zendesk-Chat connector.
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
+
import inspect
|
|
8
|
+
import json
|
|
7
9
|
import logging
|
|
8
|
-
from
|
|
10
|
+
from functools import wraps
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Callable, Mapping, TypeVar, overload
|
|
9
12
|
try:
|
|
10
13
|
from typing import Literal
|
|
11
14
|
except ImportError:
|
|
@@ -91,6 +94,38 @@ from .models import (
|
|
|
91
94
|
# TypeVar for decorator type preservation
|
|
92
95
|
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
93
96
|
|
|
97
|
+
DEFAULT_MAX_OUTPUT_CHARS = 50_000 # ~50KB default, configurable per-tool
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _raise_output_too_large(message: str) -> None:
|
|
101
|
+
try:
|
|
102
|
+
from pydantic_ai import ModelRetry # type: ignore[import-not-found]
|
|
103
|
+
except Exception as exc:
|
|
104
|
+
raise RuntimeError(message) from exc
|
|
105
|
+
raise ModelRetry(message)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _check_output_size(result: Any, max_chars: int | None, tool_name: str) -> Any:
|
|
109
|
+
if max_chars is None or max_chars <= 0:
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
serialized = json.dumps(result, default=str)
|
|
114
|
+
except (TypeError, ValueError):
|
|
115
|
+
return result
|
|
116
|
+
|
|
117
|
+
if len(serialized) > max_chars:
|
|
118
|
+
truncated_preview = serialized[:500] + "..." if len(serialized) > 500 else serialized
|
|
119
|
+
_raise_output_too_large(
|
|
120
|
+
f"Tool '{tool_name}' output too large ({len(serialized):,} chars, limit {max_chars:,}). "
|
|
121
|
+
"Please narrow your query by: using the 'fields' parameter to select only needed fields, "
|
|
122
|
+
"adding filters, or reducing the 'limit'. "
|
|
123
|
+
f"Preview: {truncated_preview}"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return result
|
|
127
|
+
|
|
128
|
+
|
|
94
129
|
|
|
95
130
|
|
|
96
131
|
class ZendeskChatConnector:
|
|
@@ -101,7 +136,7 @@ class ZendeskChatConnector:
|
|
|
101
136
|
"""
|
|
102
137
|
|
|
103
138
|
connector_name = "zendesk-chat"
|
|
104
|
-
connector_version = "0.1.
|
|
139
|
+
connector_version = "0.1.4"
|
|
105
140
|
vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
|
|
106
141
|
|
|
107
142
|
# Map of (entity, action) -> needs_envelope for envelope wrapping decision
|
|
@@ -407,15 +442,15 @@ class ZendeskChatConnector:
|
|
|
407
442
|
async def execute(
|
|
408
443
|
self,
|
|
409
444
|
entity: str,
|
|
410
|
-
action:
|
|
411
|
-
params:
|
|
445
|
+
action: Literal["get", "list", "search"],
|
|
446
|
+
params: Mapping[str, Any]
|
|
412
447
|
) -> ZendeskChatExecuteResult[Any] | ZendeskChatExecuteResultWithMeta[Any, Any] | Any: ...
|
|
413
448
|
|
|
414
449
|
async def execute(
|
|
415
450
|
self,
|
|
416
451
|
entity: str,
|
|
417
|
-
action:
|
|
418
|
-
params:
|
|
452
|
+
action: Literal["get", "list", "search"],
|
|
453
|
+
params: Mapping[str, Any] | None = None
|
|
419
454
|
) -> Any:
|
|
420
455
|
"""
|
|
421
456
|
Execute an entity operation with full type safety.
|
|
@@ -443,16 +478,17 @@ class ZendeskChatConnector:
|
|
|
443
478
|
from ._vendored.connector_sdk.executor import ExecutionConfig
|
|
444
479
|
|
|
445
480
|
# Remap parameter names from snake_case (TypedDict keys) to API parameter names
|
|
446
|
-
if params
|
|
481
|
+
resolved_params = dict(params) if params is not None else None
|
|
482
|
+
if resolved_params:
|
|
447
483
|
param_map = self._PARAM_MAP.get((entity, action), {})
|
|
448
484
|
if param_map:
|
|
449
|
-
|
|
485
|
+
resolved_params = {param_map.get(k, k): v for k, v in resolved_params.items()}
|
|
450
486
|
|
|
451
487
|
# Use ExecutionConfig for both local and hosted executors
|
|
452
488
|
config = ExecutionConfig(
|
|
453
489
|
entity=entity,
|
|
454
490
|
action=action,
|
|
455
|
-
params=
|
|
491
|
+
params=resolved_params
|
|
456
492
|
)
|
|
457
493
|
|
|
458
494
|
result = await self._executor.execute(config)
|
|
@@ -479,41 +515,67 @@ class ZendeskChatConnector:
|
|
|
479
515
|
# ===== INTROSPECTION METHODS =====
|
|
480
516
|
|
|
481
517
|
@classmethod
|
|
482
|
-
def
|
|
518
|
+
def tool_utils(
|
|
519
|
+
cls,
|
|
520
|
+
func: _F | None = None,
|
|
521
|
+
*,
|
|
522
|
+
update_docstring: bool = True,
|
|
523
|
+
max_output_chars: int | None = DEFAULT_MAX_OUTPUT_CHARS,
|
|
524
|
+
) -> _F | Callable[[_F], _F]:
|
|
483
525
|
"""
|
|
484
|
-
Decorator that
|
|
485
|
-
|
|
486
|
-
This class method can be used as a decorator to automatically generate
|
|
487
|
-
comprehensive documentation for AI tool functions.
|
|
526
|
+
Decorator that adds tool utilities like docstring augmentation and output limits.
|
|
488
527
|
|
|
489
528
|
Usage:
|
|
490
529
|
@mcp.tool()
|
|
491
|
-
@ZendeskChatConnector.
|
|
530
|
+
@ZendeskChatConnector.tool_utils
|
|
492
531
|
async def execute(entity: str, action: str, params: dict):
|
|
493
|
-
'''Execute operations.'''
|
|
494
532
|
...
|
|
495
533
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
- Example questions (if available in OpenAPI spec)
|
|
534
|
+
@mcp.tool()
|
|
535
|
+
@ZendeskChatConnector.tool_utils(update_docstring=False, max_output_chars=None)
|
|
536
|
+
async def execute(entity: str, action: str, params: dict):
|
|
537
|
+
...
|
|
501
538
|
|
|
502
539
|
Args:
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
Returns:
|
|
506
|
-
The same function with updated __doc__
|
|
540
|
+
update_docstring: When True, append connector capabilities to __doc__.
|
|
541
|
+
max_output_chars: Max serialized output size before raising. Use None to disable.
|
|
507
542
|
"""
|
|
508
|
-
description = generate_tool_description(ZendeskChatConnectorModel)
|
|
509
543
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
544
|
+
def decorate(inner: _F) -> _F:
|
|
545
|
+
if update_docstring:
|
|
546
|
+
description = generate_tool_description(ZendeskChatConnectorModel)
|
|
547
|
+
original_doc = inner.__doc__ or ""
|
|
548
|
+
if original_doc.strip():
|
|
549
|
+
full_doc = f"{original_doc.strip()}\n{description}"
|
|
550
|
+
else:
|
|
551
|
+
full_doc = description
|
|
552
|
+
else:
|
|
553
|
+
full_doc = ""
|
|
554
|
+
|
|
555
|
+
if inspect.iscoroutinefunction(inner):
|
|
556
|
+
|
|
557
|
+
@wraps(inner)
|
|
558
|
+
async def aw(*args: Any, **kwargs: Any) -> Any:
|
|
559
|
+
result = await inner(*args, **kwargs)
|
|
560
|
+
return _check_output_size(result, max_output_chars, inner.__name__)
|
|
561
|
+
|
|
562
|
+
wrapped = aw
|
|
563
|
+
else:
|
|
564
|
+
|
|
565
|
+
@wraps(inner)
|
|
566
|
+
def sw(*args: Any, **kwargs: Any) -> Any:
|
|
567
|
+
result = inner(*args, **kwargs)
|
|
568
|
+
return _check_output_size(result, max_output_chars, inner.__name__)
|
|
569
|
+
|
|
570
|
+
wrapped = sw
|
|
571
|
+
|
|
572
|
+
if update_docstring:
|
|
573
|
+
wrapped.__doc__ = full_doc
|
|
574
|
+
return wrapped # type: ignore[return-value]
|
|
515
575
|
|
|
516
|
-
|
|
576
|
+
if func is not None:
|
|
577
|
+
return decorate(func)
|
|
578
|
+
return decorate
|
|
517
579
|
|
|
518
580
|
def list_entities(self) -> list[dict[str, Any]]:
|
|
519
581
|
"""
|
|
@@ -26,7 +26,7 @@ from uuid import (
|
|
|
26
26
|
ZendeskChatConnectorModel: ConnectorModel = ConnectorModel(
|
|
27
27
|
id=UUID('40d24d0f-b8f9-4fe0-9e6c-b06c0f3f45e4'),
|
|
28
28
|
name='zendesk-chat',
|
|
29
|
-
version='0.1.
|
|
29
|
+
version='0.1.4',
|
|
30
30
|
base_url='https://{subdomain}.zendesk.com/api/v2/chat',
|
|
31
31
|
auth=AuthConfig(
|
|
32
32
|
type=AuthType.BEARER,
|
|
@@ -45,6 +45,7 @@ ZendeskChatConnectorModel: ConnectorModel = ConnectorModel(
|
|
|
45
45
|
},
|
|
46
46
|
auth_mapping={'token': '${access_token}'},
|
|
47
47
|
replication_auth_key_mapping={'credentials.access_token': 'access_token'},
|
|
48
|
+
replication_auth_key_constants={'credentials.credentials': 'access_token'},
|
|
48
49
|
),
|
|
49
50
|
),
|
|
50
51
|
entities=[
|
|
@@ -2421,4 +2422,45 @@ ZendeskChatConnectorModel: ConnectorModel = ConnectorModel(
|
|
|
2421
2422
|
},
|
|
2422
2423
|
),
|
|
2423
2424
|
],
|
|
2425
|
+
search_field_paths={
|
|
2426
|
+
'agents': [
|
|
2427
|
+
'id',
|
|
2428
|
+
'email',
|
|
2429
|
+
'display_name',
|
|
2430
|
+
'first_name',
|
|
2431
|
+
'last_name',
|
|
2432
|
+
'enabled',
|
|
2433
|
+
'role_id',
|
|
2434
|
+
'departments',
|
|
2435
|
+
'departments[]',
|
|
2436
|
+
'create_date',
|
|
2437
|
+
],
|
|
2438
|
+
'chats': [
|
|
2439
|
+
'id',
|
|
2440
|
+
'timestamp',
|
|
2441
|
+
'update_timestamp',
|
|
2442
|
+
'department_id',
|
|
2443
|
+
'department_name',
|
|
2444
|
+
'duration',
|
|
2445
|
+
'rating',
|
|
2446
|
+
'missed',
|
|
2447
|
+
'agent_ids',
|
|
2448
|
+
'agent_ids[]',
|
|
2449
|
+
],
|
|
2450
|
+
'departments': [
|
|
2451
|
+
'id',
|
|
2452
|
+
'name',
|
|
2453
|
+
'enabled',
|
|
2454
|
+
'members',
|
|
2455
|
+
'members[]',
|
|
2456
|
+
],
|
|
2457
|
+
'shortcuts': [
|
|
2458
|
+
'id',
|
|
2459
|
+
'name',
|
|
2460
|
+
'message',
|
|
2461
|
+
'tags',
|
|
2462
|
+
'tags[]',
|
|
2463
|
+
],
|
|
2464
|
+
'triggers': ['id', 'name', 'enabled'],
|
|
2465
|
+
},
|
|
2424
2466
|
)
|
|
@@ -132,27 +132,6 @@ class Ban(BaseModel):
|
|
|
132
132
|
reason: Union[str | None, Any] = Field(default=None)
|
|
133
133
|
created_at: Union[str | None, Any] = Field(default=None)
|
|
134
134
|
|
|
135
|
-
class ChatEngagement(BaseModel):
|
|
136
|
-
"""ChatEngagement type definition"""
|
|
137
|
-
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
138
|
-
|
|
139
|
-
id: Union[str | None, Any] = Field(default=None)
|
|
140
|
-
agent_id: Union[str | None, Any] = Field(default=None)
|
|
141
|
-
agent_name: Union[str | None, Any] = Field(default=None)
|
|
142
|
-
agent_full_name: Union[str | None, Any] = Field(default=None)
|
|
143
|
-
department_id: Union[int | None, Any] = Field(default=None)
|
|
144
|
-
timestamp: Union[str | None, Any] = Field(default=None)
|
|
145
|
-
duration: Union[float | None, Any] = Field(default=None)
|
|
146
|
-
accepted: Union[bool | None, Any] = Field(default=None)
|
|
147
|
-
assigned: Union[bool | None, Any] = Field(default=None)
|
|
148
|
-
started_by: Union[str | None, Any] = Field(default=None)
|
|
149
|
-
rating: Union[str | None, Any] = Field(default=None)
|
|
150
|
-
comment: Union[str | None, Any] = Field(default=None)
|
|
151
|
-
count: Union[Any, Any] = Field(default=None)
|
|
152
|
-
response_time: Union[Any, Any] = Field(default=None)
|
|
153
|
-
skills_requested: Union[list[int] | None, Any] = Field(default=None)
|
|
154
|
-
skills_fulfilled: Union[bool | None, Any] = Field(default=None)
|
|
155
|
-
|
|
156
135
|
class WebpathItem(BaseModel):
|
|
157
136
|
"""WebpathItem type definition"""
|
|
158
137
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
@@ -160,16 +139,6 @@ class WebpathItem(BaseModel):
|
|
|
160
139
|
from_: Union[str | None, Any] = Field(default=None, alias="from")
|
|
161
140
|
timestamp: Union[str | None, Any] = Field(default=None)
|
|
162
141
|
|
|
163
|
-
class ChatConversion(BaseModel):
|
|
164
|
-
"""ChatConversion type definition"""
|
|
165
|
-
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
166
|
-
|
|
167
|
-
id: Union[str | None, Any] = Field(default=None)
|
|
168
|
-
goal_id: Union[int | None, Any] = Field(default=None)
|
|
169
|
-
goal_name: Union[str | None, Any] = Field(default=None)
|
|
170
|
-
timestamp: Union[str | None, Any] = Field(default=None)
|
|
171
|
-
attribution: Union[Any, Any] = Field(default=None)
|
|
172
|
-
|
|
173
142
|
class ChatHistoryItem(BaseModel):
|
|
174
143
|
"""ChatHistoryItem type definition"""
|
|
175
144
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
@@ -189,6 +158,37 @@ class ChatHistoryItem(BaseModel):
|
|
|
189
158
|
new_tags: Union[list[str] | None, Any] = Field(default=None)
|
|
190
159
|
options: Union[str | None, Any] = Field(default=None)
|
|
191
160
|
|
|
161
|
+
class ChatConversion(BaseModel):
|
|
162
|
+
"""ChatConversion type definition"""
|
|
163
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
164
|
+
|
|
165
|
+
id: Union[str | None, Any] = Field(default=None)
|
|
166
|
+
goal_id: Union[int | None, Any] = Field(default=None)
|
|
167
|
+
goal_name: Union[str | None, Any] = Field(default=None)
|
|
168
|
+
timestamp: Union[str | None, Any] = Field(default=None)
|
|
169
|
+
attribution: Union[Any, Any] = Field(default=None)
|
|
170
|
+
|
|
171
|
+
class ChatEngagement(BaseModel):
|
|
172
|
+
"""ChatEngagement type definition"""
|
|
173
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
174
|
+
|
|
175
|
+
id: Union[str | None, Any] = Field(default=None)
|
|
176
|
+
agent_id: Union[str | None, Any] = Field(default=None)
|
|
177
|
+
agent_name: Union[str | None, Any] = Field(default=None)
|
|
178
|
+
agent_full_name: Union[str | None, Any] = Field(default=None)
|
|
179
|
+
department_id: Union[int | None, Any] = Field(default=None)
|
|
180
|
+
timestamp: Union[str | None, Any] = Field(default=None)
|
|
181
|
+
duration: Union[float | None, Any] = Field(default=None)
|
|
182
|
+
accepted: Union[bool | None, Any] = Field(default=None)
|
|
183
|
+
assigned: Union[bool | None, Any] = Field(default=None)
|
|
184
|
+
started_by: Union[str | None, Any] = Field(default=None)
|
|
185
|
+
rating: Union[str | None, Any] = Field(default=None)
|
|
186
|
+
comment: Union[str | None, Any] = Field(default=None)
|
|
187
|
+
count: Union[Any, Any] = Field(default=None)
|
|
188
|
+
response_time: Union[Any, Any] = Field(default=None)
|
|
189
|
+
skills_requested: Union[list[int] | None, Any] = Field(default=None)
|
|
190
|
+
skills_fulfilled: Union[bool | None, Any] = Field(default=None)
|
|
191
|
+
|
|
192
192
|
class Chat(BaseModel):
|
|
193
193
|
"""Chat conversation transcript"""
|
|
194
194
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
{airbyte_agent_zendesk_chat-0.1.8.dist-info → airbyte_agent_zendesk_chat-0.1.11.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-zendesk-chat
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: Airbyte Zendesk-Chat 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/
|
|
@@ -104,7 +104,7 @@ connector = ZendeskChatConnector(
|
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
107
|
-
@ZendeskChatConnector.
|
|
107
|
+
@ZendeskChatConnector.tool_utils
|
|
108
108
|
async def zendesk-chat_execute(entity: str, action: str, params: dict | None = None):
|
|
109
109
|
return await connector.execute(entity, action, params or {})
|
|
110
110
|
```
|
|
@@ -125,11 +125,15 @@ connector = ZendeskChatConnector(
|
|
|
125
125
|
)
|
|
126
126
|
|
|
127
127
|
@agent.tool_plain # assumes you're using Pydantic AI
|
|
128
|
-
@ZendeskChatConnector.
|
|
128
|
+
@ZendeskChatConnector.tool_utils
|
|
129
129
|
async def zendesk-chat_execute(entity: str, action: str, params: dict | None = None):
|
|
130
130
|
return await connector.execute(entity, action, params or {})
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
## Replication Configuration
|
|
134
|
+
|
|
135
|
+
This connector supports replication configuration for MULTI mode sources. See the [full reference documentation](./REFERENCE.md#replication-configuration) for details on available options like `start_date`.
|
|
136
|
+
|
|
133
137
|
## Full documentation
|
|
134
138
|
|
|
135
139
|
This connector supports the following entities and actions.
|
|
@@ -158,6 +162,6 @@ For the service's official API docs, see the [Zendesk-Chat API reference](https:
|
|
|
158
162
|
|
|
159
163
|
## Version information
|
|
160
164
|
|
|
161
|
-
- **Package version:** 0.1.
|
|
162
|
-
- **Connector version:** 0.1.
|
|
163
|
-
- **Generated with Connector SDK commit SHA:**
|
|
165
|
+
- **Package version:** 0.1.11
|
|
166
|
+
- **Connector version:** 0.1.4
|
|
167
|
+
- **Generated with Connector SDK commit SHA:** 609c1d86c76b36ff699b57123a5a8c2050d958c3
|
{airbyte_agent_zendesk_chat-0.1.8.dist-info → airbyte_agent_zendesk_chat-0.1.11.dist-info}/RECORD
RENAMED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
airbyte_agent_zendesk_chat/__init__.py,sha256=
|
|
2
|
-
airbyte_agent_zendesk_chat/connector.py,sha256=
|
|
3
|
-
airbyte_agent_zendesk_chat/connector_model.py,sha256=
|
|
4
|
-
airbyte_agent_zendesk_chat/models.py,sha256=
|
|
1
|
+
airbyte_agent_zendesk_chat/__init__.py,sha256=ca45IFjyP9cCDoJcdAKiVWLQKviM2sTzGOla63CPO_s,4292
|
|
2
|
+
airbyte_agent_zendesk_chat/connector.py,sha256=R_JDuiJ0kpk4_xNfgUPg1LNHlrcpYLx56Vkq8z8HesI,45365
|
|
3
|
+
airbyte_agent_zendesk_chat/connector_model.py,sha256=phL6Mh98faJyMEC9KshDl8vtJrV6cWctRvgBOoKB4Sg,122093
|
|
4
|
+
airbyte_agent_zendesk_chat/models.py,sha256=zCgNKE7xJ5OWch2fMprtInihzsk6k-rzu0myoHV2rng,23905
|
|
5
5
|
airbyte_agent_zendesk_chat/types.py,sha256=C5laH7V__abYm0F1Jck49Az6SCJQdnXLgtahxponDgM,28925
|
|
6
6
|
airbyte_agent_zendesk_chat/_vendored/__init__.py,sha256=ILl7AHXMui__swyrjxrh9yRa4dLiwBvV6axPWFWty80,38
|
|
7
7
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/__init__.py,sha256=T5o7roU6NSpH-lCAGZ338sE5dlh4ZU6i6IkeG1zpems,1949
|
|
8
8
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/auth_strategies.py,sha256=5Sb9moUp623o67Q2wMa8iZldJH08y4gQdoutoO_75Iw,42088
|
|
9
9
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/auth_template.py,sha256=nju4jqlFC_KI82ILNumNIyiUtRJcy7J94INIZ0QraI4,4454
|
|
10
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/connector_model_loader.py,sha256=
|
|
10
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/connector_model_loader.py,sha256=nCu6oym6LoKrS94NTivU1vyQE_qnU-rhx8ExpuOX_LU,39544
|
|
11
11
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/constants.py,sha256=AtzOvhDMWbRJgpsQNWl5tkogHD6mWgEY668PgRmgtOY,2737
|
|
12
12
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/exceptions.py,sha256=ss5MGv9eVPmsbLcLWetuu3sDmvturwfo6Pw3M37Oq5k,481
|
|
13
13
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/extensions.py,sha256=XWRRoJOOrwUHSKbuQt5DU7CCu8ePzhd_HuP7c_uD77w,21376
|
|
14
14
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/http_client.py,sha256=yucwu3OvJh5wLQa1mk-gTKjtqjKKucMw5ltmlE7mk1c,28000
|
|
15
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/introspection.py,sha256=
|
|
15
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/introspection.py,sha256=kRVI4TDQDLdcCnTBUML8ycAtdqAQufVh-027sMkb4i8,19165
|
|
16
16
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/secrets.py,sha256=J9ezMu4xNnLW11xY5RCre6DHP7YMKZCqwGJfk7ufHAM,6855
|
|
17
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/types.py,sha256=
|
|
17
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/types.py,sha256=in8gHsn5nsScujOfHZmkOgNmqmJKiPyNNjg59m5fGWc,8807
|
|
18
18
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/utils.py,sha256=G4LUXOC2HzPoND2v4tQW68R9uuPX9NQyCjaGxb7Kpl0,1958
|
|
19
19
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/validation.py,sha256=4MPrxYmQh8TbCU0KdvvRKe35Lg1YYLEBd0u4aKySl_E,32122
|
|
20
20
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/cloud_utils/__init__.py,sha256=4799Hv9f2zxDVj1aLyQ8JpTEuFTp_oOZMRz-NZCdBJg,134
|
|
21
21
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/cloud_utils/client.py,sha256=YxdRpQr9XjDzih6csSseBVGn9kfMtaqbOCXP0TPuzFY,7189
|
|
22
22
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/__init__.py,sha256=EmG9YQNAjSuYCVB4D5VoLm4qpD1KfeiiOf7bpALj8p8,702
|
|
23
23
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/hosted_executor.py,sha256=ydHcG-biRS1ITT5ELwPShdJW-KYpvK--Fos1ipNgHho,6995
|
|
24
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/local_executor.py,sha256=
|
|
24
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/local_executor.py,sha256=tVbfstxOrm5qJt1NawTwjhIIpDgPCC4wSrKM5eALPSQ,74064
|
|
25
25
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/models.py,sha256=lYVT_bNcw-PoIks4WHNyl2VY-lJVf2FntzINSOBIheE,5845
|
|
26
26
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/__init__.py,sha256=y8fbzZn-3yV9OxtYz8Dy6FFGI5v6TOqADd1G3xHH3Hw,911
|
|
27
27
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/config.py,sha256=6J7YIIwHC6sRu9i-yKa5XvArwK2KU60rlnmxzDZq3lw,3283
|
|
@@ -42,16 +42,16 @@ airbyte_agent_zendesk_chat/_vendored/connector_sdk/performance/__init__.py,sha25
|
|
|
42
42
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/performance/instrumentation.py,sha256=_dXvNiqdndIBwDjeDKNViWzn_M5FkSUsMmJtFldrmsM,1504
|
|
43
43
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/performance/metrics.py,sha256=FRff7dKt4iwt_A7pxV5n9kAGBR756PC7q8-weWygPSM,2817
|
|
44
44
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/__init__.py,sha256=Uymu-QuzGJuMxexBagIvUxpVAigIuIhz3KeBl_Vu4Ko,1638
|
|
45
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/base.py,sha256=
|
|
46
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/components.py,sha256=
|
|
45
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/base.py,sha256=IoAucZQ0j0xTdm4VWotB636R4jsrkYnppMQhXE0uoyU,6541
|
|
46
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/components.py,sha256=nJIPieavwX3o3ODvdtLHPk84d_V229xmg6LDfwEHjzc,8119
|
|
47
47
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/connector.py,sha256=mSZk1wr2YSdRj9tTRsPAuIlCzd_xZLw-Bzl1sMwE0rE,3731
|
|
48
|
-
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/extensions.py,sha256=
|
|
48
|
+
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/extensions.py,sha256=5hgpFHK7fzpzegCkJk882DeIP79bCx_qairKJhvPMZ8,9590
|
|
49
49
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/operations.py,sha256=RpzGtAI4yvAtMHAfMUMcUwgHv_qJojnKlNb75_agUF8,5729
|
|
50
50
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/security.py,sha256=6ljzf_JHs4amnQX9AhePcEsT8P3ZnTSC4xeg7-cvsNQ,9100
|
|
51
51
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/__init__.py,sha256=RaLgkBU4dfxn1LC5Y0Q9rr2PJbrwjxvPgBLmq8_WafE,211
|
|
52
52
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/config.py,sha256=tLmQwAFD0kP1WyBGWBS3ysaudN9H3e-3EopKZi6cGKg,885
|
|
53
53
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/events.py,sha256=8Y1NbXiwISX-V_wRofY7PqcwEXD0dLMnntKkY6XFU2s,1328
|
|
54
54
|
airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/tracker.py,sha256=Ftrk0_ddfM7dZG8hF9xBuPwhbc9D6JZ7Q9qs5o3LEyA,5579
|
|
55
|
-
airbyte_agent_zendesk_chat-0.1.
|
|
56
|
-
airbyte_agent_zendesk_chat-0.1.
|
|
57
|
-
airbyte_agent_zendesk_chat-0.1.
|
|
55
|
+
airbyte_agent_zendesk_chat-0.1.11.dist-info/METADATA,sha256=S4acOSQYD6WwXfYnRoQG4jN4eZmQE15QryY4DiefAp8,6606
|
|
56
|
+
airbyte_agent_zendesk_chat-0.1.11.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
57
|
+
airbyte_agent_zendesk_chat-0.1.11.dist-info/RECORD,,
|
{airbyte_agent_zendesk_chat-0.1.8.dist-info → airbyte_agent_zendesk_chat-0.1.11.dist-info}/WHEEL
RENAMED
|
File without changes
|