airbyte-agent-zendesk-chat 0.1.1__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.

Potentially problematic release.


This version of airbyte-agent-zendesk-chat might be problematic. Click here for more details.

Files changed (57) hide show
  1. airbyte_agent_zendesk_chat/__init__.py +193 -0
  2. airbyte_agent_zendesk_chat/_vendored/__init__.py +1 -0
  3. airbyte_agent_zendesk_chat/_vendored/connector_sdk/__init__.py +82 -0
  4. airbyte_agent_zendesk_chat/_vendored/connector_sdk/auth_strategies.py +1120 -0
  5. airbyte_agent_zendesk_chat/_vendored/connector_sdk/auth_template.py +135 -0
  6. airbyte_agent_zendesk_chat/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
  7. airbyte_agent_zendesk_chat/_vendored/connector_sdk/cloud_utils/client.py +213 -0
  8. airbyte_agent_zendesk_chat/_vendored/connector_sdk/connector_model_loader.py +965 -0
  9. airbyte_agent_zendesk_chat/_vendored/connector_sdk/constants.py +78 -0
  10. airbyte_agent_zendesk_chat/_vendored/connector_sdk/exceptions.py +23 -0
  11. airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/__init__.py +31 -0
  12. airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/hosted_executor.py +196 -0
  13. airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/local_executor.py +1724 -0
  14. airbyte_agent_zendesk_chat/_vendored/connector_sdk/executor/models.py +190 -0
  15. airbyte_agent_zendesk_chat/_vendored/connector_sdk/extensions.py +693 -0
  16. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/__init__.py +37 -0
  17. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
  18. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
  19. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/config.py +98 -0
  20. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/exceptions.py +119 -0
  21. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/protocols.py +114 -0
  22. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http/response.py +104 -0
  23. airbyte_agent_zendesk_chat/_vendored/connector_sdk/http_client.py +693 -0
  24. airbyte_agent_zendesk_chat/_vendored/connector_sdk/introspection.py +262 -0
  25. airbyte_agent_zendesk_chat/_vendored/connector_sdk/logging/__init__.py +11 -0
  26. airbyte_agent_zendesk_chat/_vendored/connector_sdk/logging/logger.py +273 -0
  27. airbyte_agent_zendesk_chat/_vendored/connector_sdk/logging/types.py +93 -0
  28. airbyte_agent_zendesk_chat/_vendored/connector_sdk/observability/__init__.py +11 -0
  29. airbyte_agent_zendesk_chat/_vendored/connector_sdk/observability/config.py +179 -0
  30. airbyte_agent_zendesk_chat/_vendored/connector_sdk/observability/models.py +19 -0
  31. airbyte_agent_zendesk_chat/_vendored/connector_sdk/observability/redactor.py +81 -0
  32. airbyte_agent_zendesk_chat/_vendored/connector_sdk/observability/session.py +103 -0
  33. airbyte_agent_zendesk_chat/_vendored/connector_sdk/performance/__init__.py +6 -0
  34. airbyte_agent_zendesk_chat/_vendored/connector_sdk/performance/instrumentation.py +57 -0
  35. airbyte_agent_zendesk_chat/_vendored/connector_sdk/performance/metrics.py +93 -0
  36. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/__init__.py +75 -0
  37. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/base.py +164 -0
  38. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/components.py +239 -0
  39. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/connector.py +120 -0
  40. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/extensions.py +230 -0
  41. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/operations.py +146 -0
  42. airbyte_agent_zendesk_chat/_vendored/connector_sdk/schema/security.py +223 -0
  43. airbyte_agent_zendesk_chat/_vendored/connector_sdk/secrets.py +182 -0
  44. airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/__init__.py +10 -0
  45. airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/config.py +32 -0
  46. airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/events.py +59 -0
  47. airbyte_agent_zendesk_chat/_vendored/connector_sdk/telemetry/tracker.py +155 -0
  48. airbyte_agent_zendesk_chat/_vendored/connector_sdk/types.py +245 -0
  49. airbyte_agent_zendesk_chat/_vendored/connector_sdk/utils.py +60 -0
  50. airbyte_agent_zendesk_chat/_vendored/connector_sdk/validation.py +828 -0
  51. airbyte_agent_zendesk_chat/connector.py +1465 -0
  52. airbyte_agent_zendesk_chat/connector_model.py +2424 -0
  53. airbyte_agent_zendesk_chat/models.py +582 -0
  54. airbyte_agent_zendesk_chat/types.py +984 -0
  55. airbyte_agent_zendesk_chat-0.1.1.dist-info/METADATA +130 -0
  56. airbyte_agent_zendesk_chat-0.1.1.dist-info/RECORD +57 -0
  57. airbyte_agent_zendesk_chat-0.1.1.dist-info/WHEEL +4 -0
@@ -0,0 +1,1465 @@
1
+ """
2
+ Zendesk-Chat connector.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import logging
8
+ from typing import TYPE_CHECKING, Any, Callable, TypeVar, overload
9
+ try:
10
+ from typing import Literal
11
+ except ImportError:
12
+ from typing_extensions import Literal
13
+
14
+ from .connector_model import ZendeskChatConnectorModel
15
+ from ._vendored.connector_sdk.introspection import describe_entities, generate_tool_description
16
+ from .types import (
17
+ AccountsGetParams,
18
+ AgentTimelineListParams,
19
+ AgentsGetParams,
20
+ AgentsListParams,
21
+ BansGetParams,
22
+ BansListParams,
23
+ ChatsGetParams,
24
+ ChatsListParams,
25
+ DepartmentsGetParams,
26
+ DepartmentsListParams,
27
+ GoalsGetParams,
28
+ GoalsListParams,
29
+ RolesGetParams,
30
+ RolesListParams,
31
+ RoutingSettingsGetParams,
32
+ ShortcutsGetParams,
33
+ ShortcutsListParams,
34
+ SkillsGetParams,
35
+ SkillsListParams,
36
+ TriggersListParams,
37
+ AirbyteSearchParams,
38
+ AgentsSearchFilter,
39
+ AgentsSearchQuery,
40
+ ChatsSearchFilter,
41
+ ChatsSearchQuery,
42
+ DepartmentsSearchFilter,
43
+ DepartmentsSearchQuery,
44
+ ShortcutsSearchFilter,
45
+ ShortcutsSearchQuery,
46
+ TriggersSearchFilter,
47
+ TriggersSearchQuery,
48
+ )
49
+ if TYPE_CHECKING:
50
+ from .models import ZendeskChatAuthConfig
51
+ # Import response models and envelope models at runtime
52
+ from .models import (
53
+ ZendeskChatExecuteResult,
54
+ ZendeskChatExecuteResultWithMeta,
55
+ AgentsListResult,
56
+ AgentTimelineListResult,
57
+ BansListResult,
58
+ ChatsListResult,
59
+ DepartmentsListResult,
60
+ GoalsListResult,
61
+ RolesListResult,
62
+ ShortcutsListResult,
63
+ SkillsListResult,
64
+ TriggersListResult,
65
+ Account,
66
+ Agent,
67
+ AgentTimeline,
68
+ Ban,
69
+ Chat,
70
+ Department,
71
+ Goal,
72
+ Role,
73
+ RoutingSettings,
74
+ Shortcut,
75
+ Skill,
76
+ Trigger,
77
+ AirbyteSearchHit,
78
+ AirbyteSearchResult,
79
+ AgentsSearchData,
80
+ AgentsSearchResult,
81
+ ChatsSearchData,
82
+ ChatsSearchResult,
83
+ DepartmentsSearchData,
84
+ DepartmentsSearchResult,
85
+ ShortcutsSearchData,
86
+ ShortcutsSearchResult,
87
+ TriggersSearchData,
88
+ TriggersSearchResult,
89
+ )
90
+
91
+ # TypeVar for decorator type preservation
92
+ _F = TypeVar("_F", bound=Callable[..., Any])
93
+
94
+
95
+
96
+ class ZendeskChatConnector:
97
+ """
98
+ Type-safe Zendesk-Chat API connector.
99
+
100
+ Auto-generated from OpenAPI specification with full type safety.
101
+ """
102
+
103
+ connector_name = "zendesk-chat"
104
+ connector_version = "0.1.2"
105
+ vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
106
+
107
+ # Map of (entity, action) -> needs_envelope for envelope wrapping decision
108
+ _ENVELOPE_MAP = {
109
+ ("accounts", "get"): None,
110
+ ("agents", "list"): True,
111
+ ("agents", "get"): None,
112
+ ("agent_timeline", "list"): True,
113
+ ("bans", "list"): True,
114
+ ("bans", "get"): None,
115
+ ("chats", "list"): True,
116
+ ("chats", "get"): None,
117
+ ("departments", "list"): True,
118
+ ("departments", "get"): None,
119
+ ("goals", "list"): True,
120
+ ("goals", "get"): None,
121
+ ("roles", "list"): True,
122
+ ("roles", "get"): None,
123
+ ("routing_settings", "get"): None,
124
+ ("shortcuts", "list"): True,
125
+ ("shortcuts", "get"): None,
126
+ ("skills", "list"): True,
127
+ ("skills", "get"): None,
128
+ ("triggers", "list"): True,
129
+ }
130
+
131
+ # Map of (entity, action) -> {python_param_name: api_param_name}
132
+ # Used to convert snake_case TypedDict keys to API parameter names in execute()
133
+ _PARAM_MAP = {
134
+ ('agents', 'list'): {'limit': 'limit', 'since_id': 'since_id'},
135
+ ('agents', 'get'): {'agent_id': 'agent_id'},
136
+ ('agent_timeline', 'list'): {'start_time': 'start_time', 'limit': 'limit', 'fields': 'fields'},
137
+ ('bans', 'list'): {'limit': 'limit', 'since_id': 'since_id'},
138
+ ('bans', 'get'): {'ban_id': 'ban_id'},
139
+ ('chats', 'list'): {'start_time': 'start_time', 'limit': 'limit', 'fields': 'fields'},
140
+ ('chats', 'get'): {'chat_id': 'chat_id'},
141
+ ('departments', 'get'): {'department_id': 'department_id'},
142
+ ('goals', 'get'): {'goal_id': 'goal_id'},
143
+ ('roles', 'get'): {'role_id': 'role_id'},
144
+ ('shortcuts', 'get'): {'shortcut_id': 'shortcut_id'},
145
+ ('skills', 'get'): {'skill_id': 'skill_id'},
146
+ }
147
+
148
+ def __init__(
149
+ self,
150
+ auth_config: ZendeskChatAuthConfig | None = None,
151
+ external_user_id: str | None = None,
152
+ airbyte_client_id: str | None = None,
153
+ airbyte_client_secret: str | None = None,
154
+ on_token_refresh: Any | None = None,
155
+ subdomain: str | None = None ):
156
+ """
157
+ Initialize a new zendesk-chat connector instance.
158
+
159
+ Supports both local and hosted execution modes:
160
+ - Local mode: Provide `auth_config` for direct API calls
161
+ - Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
162
+
163
+ Args:
164
+ auth_config: Typed authentication configuration (required for local mode)
165
+ external_user_id: External user ID (required for hosted mode)
166
+ airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
167
+ airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
168
+ on_token_refresh: Optional callback for OAuth2 token refresh persistence.
169
+ Called with new_tokens dict when tokens are refreshed. Can be sync or async.
170
+ Example: lambda tokens: save_to_database(tokens) subdomain: Your Zendesk subdomain (the part before .zendesk.com in your Zendesk URL)
171
+ Examples:
172
+ # Local mode (direct API calls)
173
+ connector = ZendeskChatConnector(auth_config=ZendeskChatAuthConfig(access_token="..."))
174
+ # Hosted mode (executed on Airbyte cloud)
175
+ connector = ZendeskChatConnector(
176
+ external_user_id="user-123",
177
+ airbyte_client_id="client_abc123",
178
+ airbyte_client_secret="secret_xyz789"
179
+ )
180
+
181
+ # Local mode with OAuth2 token refresh callback
182
+ def save_tokens(new_tokens: dict) -> None:
183
+ # Persist updated tokens to your storage (file, database, etc.)
184
+ with open("tokens.json", "w") as f:
185
+ json.dump(new_tokens, f)
186
+
187
+ connector = ZendeskChatConnector(
188
+ auth_config=ZendeskChatAuthConfig(access_token="...", refresh_token="..."),
189
+ on_token_refresh=save_tokens
190
+ )
191
+ """
192
+ # Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
193
+ if external_user_id and airbyte_client_id and airbyte_client_secret:
194
+ from ._vendored.connector_sdk.executor import HostedExecutor
195
+ self._executor = HostedExecutor(
196
+ external_user_id=external_user_id,
197
+ airbyte_client_id=airbyte_client_id,
198
+ airbyte_client_secret=airbyte_client_secret,
199
+ connector_definition_id=str(ZendeskChatConnectorModel.id),
200
+ )
201
+ else:
202
+ # Local mode: auth_config required
203
+ if not auth_config:
204
+ raise ValueError(
205
+ "Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
206
+ "or auth_config for local mode"
207
+ )
208
+
209
+ from ._vendored.connector_sdk.executor import LocalExecutor
210
+
211
+ # Build config_values dict from server variables
212
+ config_values: dict[str, str] = {}
213
+ if subdomain:
214
+ config_values["subdomain"] = subdomain
215
+
216
+ self._executor = LocalExecutor(
217
+ model=ZendeskChatConnectorModel,
218
+ auth_config=auth_config.model_dump() if auth_config else None,
219
+ config_values=config_values,
220
+ on_token_refresh=on_token_refresh
221
+ )
222
+
223
+ # Update base_url with server variables if provided
224
+ base_url = self._executor.http_client.base_url
225
+ if subdomain:
226
+ base_url = base_url.replace("{subdomain}", subdomain)
227
+ self._executor.http_client.base_url = base_url
228
+
229
+ # Initialize entity query objects
230
+ self.accounts = AccountsQuery(self)
231
+ self.agents = AgentsQuery(self)
232
+ self.agent_timeline = AgentTimelineQuery(self)
233
+ self.bans = BansQuery(self)
234
+ self.chats = ChatsQuery(self)
235
+ self.departments = DepartmentsQuery(self)
236
+ self.goals = GoalsQuery(self)
237
+ self.roles = RolesQuery(self)
238
+ self.routing_settings = RoutingSettingsQuery(self)
239
+ self.shortcuts = ShortcutsQuery(self)
240
+ self.skills = SkillsQuery(self)
241
+ self.triggers = TriggersQuery(self)
242
+
243
+ # ===== TYPED EXECUTE METHOD (Recommended Interface) =====
244
+
245
+ @overload
246
+ async def execute(
247
+ self,
248
+ entity: Literal["accounts"],
249
+ action: Literal["get"],
250
+ params: "AccountsGetParams"
251
+ ) -> "Account": ...
252
+
253
+ @overload
254
+ async def execute(
255
+ self,
256
+ entity: Literal["agents"],
257
+ action: Literal["list"],
258
+ params: "AgentsListParams"
259
+ ) -> "AgentsListResult": ...
260
+
261
+ @overload
262
+ async def execute(
263
+ self,
264
+ entity: Literal["agents"],
265
+ action: Literal["get"],
266
+ params: "AgentsGetParams"
267
+ ) -> "Agent": ...
268
+
269
+ @overload
270
+ async def execute(
271
+ self,
272
+ entity: Literal["agent_timeline"],
273
+ action: Literal["list"],
274
+ params: "AgentTimelineListParams"
275
+ ) -> "AgentTimelineListResult": ...
276
+
277
+ @overload
278
+ async def execute(
279
+ self,
280
+ entity: Literal["bans"],
281
+ action: Literal["list"],
282
+ params: "BansListParams"
283
+ ) -> "BansListResult": ...
284
+
285
+ @overload
286
+ async def execute(
287
+ self,
288
+ entity: Literal["bans"],
289
+ action: Literal["get"],
290
+ params: "BansGetParams"
291
+ ) -> "Ban": ...
292
+
293
+ @overload
294
+ async def execute(
295
+ self,
296
+ entity: Literal["chats"],
297
+ action: Literal["list"],
298
+ params: "ChatsListParams"
299
+ ) -> "ChatsListResult": ...
300
+
301
+ @overload
302
+ async def execute(
303
+ self,
304
+ entity: Literal["chats"],
305
+ action: Literal["get"],
306
+ params: "ChatsGetParams"
307
+ ) -> "Chat": ...
308
+
309
+ @overload
310
+ async def execute(
311
+ self,
312
+ entity: Literal["departments"],
313
+ action: Literal["list"],
314
+ params: "DepartmentsListParams"
315
+ ) -> "DepartmentsListResult": ...
316
+
317
+ @overload
318
+ async def execute(
319
+ self,
320
+ entity: Literal["departments"],
321
+ action: Literal["get"],
322
+ params: "DepartmentsGetParams"
323
+ ) -> "Department": ...
324
+
325
+ @overload
326
+ async def execute(
327
+ self,
328
+ entity: Literal["goals"],
329
+ action: Literal["list"],
330
+ params: "GoalsListParams"
331
+ ) -> "GoalsListResult": ...
332
+
333
+ @overload
334
+ async def execute(
335
+ self,
336
+ entity: Literal["goals"],
337
+ action: Literal["get"],
338
+ params: "GoalsGetParams"
339
+ ) -> "Goal": ...
340
+
341
+ @overload
342
+ async def execute(
343
+ self,
344
+ entity: Literal["roles"],
345
+ action: Literal["list"],
346
+ params: "RolesListParams"
347
+ ) -> "RolesListResult": ...
348
+
349
+ @overload
350
+ async def execute(
351
+ self,
352
+ entity: Literal["roles"],
353
+ action: Literal["get"],
354
+ params: "RolesGetParams"
355
+ ) -> "Role": ...
356
+
357
+ @overload
358
+ async def execute(
359
+ self,
360
+ entity: Literal["routing_settings"],
361
+ action: Literal["get"],
362
+ params: "RoutingSettingsGetParams"
363
+ ) -> "RoutingSettings": ...
364
+
365
+ @overload
366
+ async def execute(
367
+ self,
368
+ entity: Literal["shortcuts"],
369
+ action: Literal["list"],
370
+ params: "ShortcutsListParams"
371
+ ) -> "ShortcutsListResult": ...
372
+
373
+ @overload
374
+ async def execute(
375
+ self,
376
+ entity: Literal["shortcuts"],
377
+ action: Literal["get"],
378
+ params: "ShortcutsGetParams"
379
+ ) -> "Shortcut": ...
380
+
381
+ @overload
382
+ async def execute(
383
+ self,
384
+ entity: Literal["skills"],
385
+ action: Literal["list"],
386
+ params: "SkillsListParams"
387
+ ) -> "SkillsListResult": ...
388
+
389
+ @overload
390
+ async def execute(
391
+ self,
392
+ entity: Literal["skills"],
393
+ action: Literal["get"],
394
+ params: "SkillsGetParams"
395
+ ) -> "Skill": ...
396
+
397
+ @overload
398
+ async def execute(
399
+ self,
400
+ entity: Literal["triggers"],
401
+ action: Literal["list"],
402
+ params: "TriggersListParams"
403
+ ) -> "TriggersListResult": ...
404
+
405
+
406
+ @overload
407
+ async def execute(
408
+ self,
409
+ entity: str,
410
+ action: str,
411
+ params: dict[str, Any]
412
+ ) -> ZendeskChatExecuteResult[Any] | ZendeskChatExecuteResultWithMeta[Any, Any] | Any: ...
413
+
414
+ async def execute(
415
+ self,
416
+ entity: str,
417
+ action: str,
418
+ params: dict[str, Any] | None = None
419
+ ) -> Any:
420
+ """
421
+ Execute an entity operation with full type safety.
422
+
423
+ This is the recommended interface for blessed connectors as it:
424
+ - Uses the same signature as non-blessed connectors
425
+ - Provides full IDE autocomplete for entity/action/params
426
+ - Makes migration from generic to blessed connectors seamless
427
+
428
+ Args:
429
+ entity: Entity name (e.g., "customers")
430
+ action: Operation action (e.g., "create", "get", "list")
431
+ params: Operation parameters (typed based on entity+action)
432
+
433
+ Returns:
434
+ Typed response based on the operation
435
+
436
+ Example:
437
+ customer = await connector.execute(
438
+ entity="customers",
439
+ action="get",
440
+ params={"id": "cus_123"}
441
+ )
442
+ """
443
+ from ._vendored.connector_sdk.executor import ExecutionConfig
444
+
445
+ # Remap parameter names from snake_case (TypedDict keys) to API parameter names
446
+ if params:
447
+ param_map = self._PARAM_MAP.get((entity, action), {})
448
+ if param_map:
449
+ params = {param_map.get(k, k): v for k, v in params.items()}
450
+
451
+ # Use ExecutionConfig for both local and hosted executors
452
+ config = ExecutionConfig(
453
+ entity=entity,
454
+ action=action,
455
+ params=params
456
+ )
457
+
458
+ result = await self._executor.execute(config)
459
+
460
+ if not result.success:
461
+ raise RuntimeError(f"Execution failed: {result.error}")
462
+
463
+ # Check if this operation has extractors configured
464
+ has_extractors = self._ENVELOPE_MAP.get((entity, action), False)
465
+
466
+ if has_extractors:
467
+ # With extractors - return Pydantic envelope with data and meta
468
+ if result.meta is not None:
469
+ return ZendeskChatExecuteResultWithMeta[Any, Any](
470
+ data=result.data,
471
+ meta=result.meta
472
+ )
473
+ else:
474
+ return ZendeskChatExecuteResult[Any](data=result.data)
475
+ else:
476
+ # No extractors - return raw response data
477
+ return result.data
478
+
479
+ # ===== INTROSPECTION METHODS =====
480
+
481
+ @classmethod
482
+ def describe(cls, func: _F) -> _F:
483
+ """
484
+ Decorator that populates a function's docstring with connector capabilities.
485
+
486
+ This class method can be used as a decorator to automatically generate
487
+ comprehensive documentation for AI tool functions.
488
+
489
+ Usage:
490
+ @mcp.tool()
491
+ @ZendeskChatConnector.describe
492
+ async def execute(entity: str, action: str, params: dict):
493
+ '''Execute operations.'''
494
+ ...
495
+
496
+ The decorated function's __doc__ will be updated with:
497
+ - Available entities and their actions
498
+ - Parameter signatures with required (*) and optional (?) markers
499
+ - Response structure documentation
500
+ - Example questions (if available in OpenAPI spec)
501
+
502
+ Args:
503
+ func: The function to decorate
504
+
505
+ Returns:
506
+ The same function with updated __doc__
507
+ """
508
+ description = generate_tool_description(ZendeskChatConnectorModel)
509
+
510
+ original_doc = func.__doc__ or ""
511
+ if original_doc.strip():
512
+ func.__doc__ = f"{original_doc.strip()}\n{description}"
513
+ else:
514
+ func.__doc__ = description
515
+
516
+ return func
517
+
518
+ def list_entities(self) -> list[dict[str, Any]]:
519
+ """
520
+ Get structured data about available entities, actions, and parameters.
521
+
522
+ Returns a list of entity descriptions with:
523
+ - entity_name: Name of the entity (e.g., "contacts", "deals")
524
+ - description: Entity description from the first endpoint
525
+ - available_actions: List of actions (e.g., ["list", "get", "create"])
526
+ - parameters: Dict mapping action -> list of parameter dicts
527
+
528
+ Example:
529
+ entities = connector.list_entities()
530
+ for entity in entities:
531
+ print(f"{entity['entity_name']}: {entity['available_actions']}")
532
+ """
533
+ return describe_entities(ZendeskChatConnectorModel)
534
+
535
+ def entity_schema(self, entity: str) -> dict[str, Any] | None:
536
+ """
537
+ Get the JSON schema for an entity.
538
+
539
+ Args:
540
+ entity: Entity name (e.g., "contacts", "companies")
541
+
542
+ Returns:
543
+ JSON schema dict describing the entity structure, or None if not found.
544
+
545
+ Example:
546
+ schema = connector.entity_schema("contacts")
547
+ if schema:
548
+ print(f"Contact properties: {list(schema.get('properties', {}).keys())}")
549
+ """
550
+ entity_def = next(
551
+ (e for e in ZendeskChatConnectorModel.entities if e.name == entity),
552
+ None
553
+ )
554
+ if entity_def is None:
555
+ logging.getLogger(__name__).warning(
556
+ f"Entity '{entity}' not found. Available entities: "
557
+ f"{[e.name for e in ZendeskChatConnectorModel.entities]}"
558
+ )
559
+ return entity_def.entity_schema if entity_def else None
560
+
561
+
562
+
563
+ class AccountsQuery:
564
+ """
565
+ Query class for Accounts entity operations.
566
+ """
567
+
568
+ def __init__(self, connector: ZendeskChatConnector):
569
+ """Initialize query with connector reference."""
570
+ self._connector = connector
571
+
572
+ async def get(
573
+ self,
574
+ **kwargs
575
+ ) -> Account:
576
+ """
577
+ Returns the account information for the authenticated user
578
+
579
+ Returns:
580
+ Account
581
+ """
582
+ params = {k: v for k, v in {
583
+ **kwargs
584
+ }.items() if v is not None}
585
+
586
+ result = await self._connector.execute("accounts", "get", params)
587
+ return result
588
+
589
+
590
+
591
+ class AgentsQuery:
592
+ """
593
+ Query class for Agents entity operations.
594
+ """
595
+
596
+ def __init__(self, connector: ZendeskChatConnector):
597
+ """Initialize query with connector reference."""
598
+ self._connector = connector
599
+
600
+ async def list(
601
+ self,
602
+ limit: int | None = None,
603
+ since_id: int | None = None,
604
+ **kwargs
605
+ ) -> AgentsListResult:
606
+ """
607
+ List all agents
608
+
609
+ Args:
610
+ limit: Parameter limit
611
+ since_id: Parameter since_id
612
+ **kwargs: Additional parameters
613
+
614
+ Returns:
615
+ AgentsListResult
616
+ """
617
+ params = {k: v for k, v in {
618
+ "limit": limit,
619
+ "since_id": since_id,
620
+ **kwargs
621
+ }.items() if v is not None}
622
+
623
+ result = await self._connector.execute("agents", "list", params)
624
+ # Cast generic envelope to concrete typed result
625
+ return AgentsListResult(
626
+ data=result.data
627
+ )
628
+
629
+
630
+
631
+ async def get(
632
+ self,
633
+ agent_id: str,
634
+ **kwargs
635
+ ) -> Agent:
636
+ """
637
+ Get an agent
638
+
639
+ Args:
640
+ agent_id: Parameter agent_id
641
+ **kwargs: Additional parameters
642
+
643
+ Returns:
644
+ Agent
645
+ """
646
+ params = {k: v for k, v in {
647
+ "agent_id": agent_id,
648
+ **kwargs
649
+ }.items() if v is not None}
650
+
651
+ result = await self._connector.execute("agents", "get", params)
652
+ return result
653
+
654
+
655
+
656
+ async def search(
657
+ self,
658
+ query: AgentsSearchQuery,
659
+ limit: int | None = None,
660
+ cursor: str | None = None,
661
+ fields: list[list[str]] | None = None,
662
+ ) -> AgentsSearchResult:
663
+ """
664
+ Search agents records from Airbyte cache.
665
+
666
+ This operation searches cached data from Airbyte syncs.
667
+ Only available in hosted execution mode.
668
+
669
+ Available filter fields (AgentsSearchFilter):
670
+ - id: Unique agent identifier
671
+ - email: Agent email address
672
+ - display_name: Agent display name
673
+ - first_name: Agent first name
674
+ - last_name: Agent last name
675
+ - enabled: Whether agent is enabled
676
+ - role_id: Agent role ID
677
+ - departments: Department IDs agent belongs to
678
+ - create_date: When agent was created
679
+
680
+ Args:
681
+ query: Filter and sort conditions. Supports operators like eq, neq, gt, gte, lt, lte,
682
+ in, like, fuzzy, keyword, not, and, or. Example: {"filter": {"eq": {"status": "active"}}}
683
+ limit: Maximum results to return (default 1000)
684
+ cursor: Pagination cursor from previous response's next_cursor
685
+ fields: Field paths to include in results. Each path is a list of keys for nested access.
686
+ Example: [["id"], ["user", "name"]] returns id and user.name fields.
687
+
688
+ Returns:
689
+ AgentsSearchResult with hits (list of AirbyteSearchHit[AgentsSearchData]) and pagination info
690
+
691
+ Raises:
692
+ NotImplementedError: If called in local execution mode
693
+ """
694
+ params: dict[str, Any] = {"query": query}
695
+ if limit is not None:
696
+ params["limit"] = limit
697
+ if cursor is not None:
698
+ params["cursor"] = cursor
699
+ if fields is not None:
700
+ params["fields"] = fields
701
+
702
+ result = await self._connector.execute("agents", "search", params)
703
+
704
+ # Parse response into typed result
705
+ return AgentsSearchResult(
706
+ hits=[
707
+ AirbyteSearchHit[AgentsSearchData](
708
+ id=hit.get("id"),
709
+ score=hit.get("score"),
710
+ data=AgentsSearchData(**hit.get("data", {}))
711
+ )
712
+ for hit in result.get("hits", [])
713
+ ],
714
+ next_cursor=result.get("next_cursor"),
715
+ took_ms=result.get("took_ms")
716
+ )
717
+
718
+ class AgentTimelineQuery:
719
+ """
720
+ Query class for AgentTimeline entity operations.
721
+ """
722
+
723
+ def __init__(self, connector: ZendeskChatConnector):
724
+ """Initialize query with connector reference."""
725
+ self._connector = connector
726
+
727
+ async def list(
728
+ self,
729
+ start_time: int | None = None,
730
+ limit: int | None = None,
731
+ fields: str | None = None,
732
+ **kwargs
733
+ ) -> AgentTimelineListResult:
734
+ """
735
+ List agent timeline (incremental export)
736
+
737
+ Args:
738
+ start_time: Parameter start_time
739
+ limit: Parameter limit
740
+ fields: Parameter fields
741
+ **kwargs: Additional parameters
742
+
743
+ Returns:
744
+ AgentTimelineListResult
745
+ """
746
+ params = {k: v for k, v in {
747
+ "start_time": start_time,
748
+ "limit": limit,
749
+ "fields": fields,
750
+ **kwargs
751
+ }.items() if v is not None}
752
+
753
+ result = await self._connector.execute("agent_timeline", "list", params)
754
+ # Cast generic envelope to concrete typed result
755
+ return AgentTimelineListResult(
756
+ data=result.data,
757
+ meta=result.meta
758
+ )
759
+
760
+
761
+
762
+ class BansQuery:
763
+ """
764
+ Query class for Bans entity operations.
765
+ """
766
+
767
+ def __init__(self, connector: ZendeskChatConnector):
768
+ """Initialize query with connector reference."""
769
+ self._connector = connector
770
+
771
+ async def list(
772
+ self,
773
+ limit: int | None = None,
774
+ since_id: int | None = None,
775
+ **kwargs
776
+ ) -> BansListResult:
777
+ """
778
+ List all bans
779
+
780
+ Args:
781
+ limit: Parameter limit
782
+ since_id: Parameter since_id
783
+ **kwargs: Additional parameters
784
+
785
+ Returns:
786
+ BansListResult
787
+ """
788
+ params = {k: v for k, v in {
789
+ "limit": limit,
790
+ "since_id": since_id,
791
+ **kwargs
792
+ }.items() if v is not None}
793
+
794
+ result = await self._connector.execute("bans", "list", params)
795
+ # Cast generic envelope to concrete typed result
796
+ return BansListResult(
797
+ data=result.data
798
+ )
799
+
800
+
801
+
802
+ async def get(
803
+ self,
804
+ ban_id: str,
805
+ **kwargs
806
+ ) -> Ban:
807
+ """
808
+ Get a ban
809
+
810
+ Args:
811
+ ban_id: Parameter ban_id
812
+ **kwargs: Additional parameters
813
+
814
+ Returns:
815
+ Ban
816
+ """
817
+ params = {k: v for k, v in {
818
+ "ban_id": ban_id,
819
+ **kwargs
820
+ }.items() if v is not None}
821
+
822
+ result = await self._connector.execute("bans", "get", params)
823
+ return result
824
+
825
+
826
+
827
+ class ChatsQuery:
828
+ """
829
+ Query class for Chats entity operations.
830
+ """
831
+
832
+ def __init__(self, connector: ZendeskChatConnector):
833
+ """Initialize query with connector reference."""
834
+ self._connector = connector
835
+
836
+ async def list(
837
+ self,
838
+ start_time: int | None = None,
839
+ limit: int | None = None,
840
+ fields: str | None = None,
841
+ **kwargs
842
+ ) -> ChatsListResult:
843
+ """
844
+ List chats (incremental export)
845
+
846
+ Args:
847
+ start_time: Parameter start_time
848
+ limit: Parameter limit
849
+ fields: Parameter fields
850
+ **kwargs: Additional parameters
851
+
852
+ Returns:
853
+ ChatsListResult
854
+ """
855
+ params = {k: v for k, v in {
856
+ "start_time": start_time,
857
+ "limit": limit,
858
+ "fields": fields,
859
+ **kwargs
860
+ }.items() if v is not None}
861
+
862
+ result = await self._connector.execute("chats", "list", params)
863
+ # Cast generic envelope to concrete typed result
864
+ return ChatsListResult(
865
+ data=result.data,
866
+ meta=result.meta
867
+ )
868
+
869
+
870
+
871
+ async def get(
872
+ self,
873
+ chat_id: str,
874
+ **kwargs
875
+ ) -> Chat:
876
+ """
877
+ Get a chat
878
+
879
+ Args:
880
+ chat_id: Parameter chat_id
881
+ **kwargs: Additional parameters
882
+
883
+ Returns:
884
+ Chat
885
+ """
886
+ params = {k: v for k, v in {
887
+ "chat_id": chat_id,
888
+ **kwargs
889
+ }.items() if v is not None}
890
+
891
+ result = await self._connector.execute("chats", "get", params)
892
+ return result
893
+
894
+
895
+
896
+ async def search(
897
+ self,
898
+ query: ChatsSearchQuery,
899
+ limit: int | None = None,
900
+ cursor: str | None = None,
901
+ fields: list[list[str]] | None = None,
902
+ ) -> ChatsSearchResult:
903
+ """
904
+ Search chats records from Airbyte cache.
905
+
906
+ This operation searches cached data from Airbyte syncs.
907
+ Only available in hosted execution mode.
908
+
909
+ Available filter fields (ChatsSearchFilter):
910
+ - id: Unique chat identifier
911
+ - timestamp: Chat start timestamp
912
+ - update_timestamp: Last update timestamp
913
+ - department_id: Department ID
914
+ - department_name: Department name
915
+ - duration: Chat duration in seconds
916
+ - rating: Satisfaction rating
917
+ - missed: Whether chat was missed
918
+ - agent_ids: IDs of agents in chat
919
+
920
+ Args:
921
+ query: Filter and sort conditions. Supports operators like eq, neq, gt, gte, lt, lte,
922
+ in, like, fuzzy, keyword, not, and, or. Example: {"filter": {"eq": {"status": "active"}}}
923
+ limit: Maximum results to return (default 1000)
924
+ cursor: Pagination cursor from previous response's next_cursor
925
+ fields: Field paths to include in results. Each path is a list of keys for nested access.
926
+ Example: [["id"], ["user", "name"]] returns id and user.name fields.
927
+
928
+ Returns:
929
+ ChatsSearchResult with hits (list of AirbyteSearchHit[ChatsSearchData]) and pagination info
930
+
931
+ Raises:
932
+ NotImplementedError: If called in local execution mode
933
+ """
934
+ params: dict[str, Any] = {"query": query}
935
+ if limit is not None:
936
+ params["limit"] = limit
937
+ if cursor is not None:
938
+ params["cursor"] = cursor
939
+ if fields is not None:
940
+ params["fields"] = fields
941
+
942
+ result = await self._connector.execute("chats", "search", params)
943
+
944
+ # Parse response into typed result
945
+ return ChatsSearchResult(
946
+ hits=[
947
+ AirbyteSearchHit[ChatsSearchData](
948
+ id=hit.get("id"),
949
+ score=hit.get("score"),
950
+ data=ChatsSearchData(**hit.get("data", {}))
951
+ )
952
+ for hit in result.get("hits", [])
953
+ ],
954
+ next_cursor=result.get("next_cursor"),
955
+ took_ms=result.get("took_ms")
956
+ )
957
+
958
+ class DepartmentsQuery:
959
+ """
960
+ Query class for Departments entity operations.
961
+ """
962
+
963
+ def __init__(self, connector: ZendeskChatConnector):
964
+ """Initialize query with connector reference."""
965
+ self._connector = connector
966
+
967
+ async def list(
968
+ self,
969
+ **kwargs
970
+ ) -> DepartmentsListResult:
971
+ """
972
+ List all departments
973
+
974
+ Returns:
975
+ DepartmentsListResult
976
+ """
977
+ params = {k: v for k, v in {
978
+ **kwargs
979
+ }.items() if v is not None}
980
+
981
+ result = await self._connector.execute("departments", "list", params)
982
+ # Cast generic envelope to concrete typed result
983
+ return DepartmentsListResult(
984
+ data=result.data
985
+ )
986
+
987
+
988
+
989
+ async def get(
990
+ self,
991
+ department_id: str,
992
+ **kwargs
993
+ ) -> Department:
994
+ """
995
+ Get a department
996
+
997
+ Args:
998
+ department_id: Parameter department_id
999
+ **kwargs: Additional parameters
1000
+
1001
+ Returns:
1002
+ Department
1003
+ """
1004
+ params = {k: v for k, v in {
1005
+ "department_id": department_id,
1006
+ **kwargs
1007
+ }.items() if v is not None}
1008
+
1009
+ result = await self._connector.execute("departments", "get", params)
1010
+ return result
1011
+
1012
+
1013
+
1014
+ async def search(
1015
+ self,
1016
+ query: DepartmentsSearchQuery,
1017
+ limit: int | None = None,
1018
+ cursor: str | None = None,
1019
+ fields: list[list[str]] | None = None,
1020
+ ) -> DepartmentsSearchResult:
1021
+ """
1022
+ Search departments records from Airbyte cache.
1023
+
1024
+ This operation searches cached data from Airbyte syncs.
1025
+ Only available in hosted execution mode.
1026
+
1027
+ Available filter fields (DepartmentsSearchFilter):
1028
+ - id: Department ID
1029
+ - name: Department name
1030
+ - enabled: Whether department is enabled
1031
+ - members: Agent IDs in department
1032
+
1033
+ Args:
1034
+ query: Filter and sort conditions. Supports operators like eq, neq, gt, gte, lt, lte,
1035
+ in, like, fuzzy, keyword, not, and, or. Example: {"filter": {"eq": {"status": "active"}}}
1036
+ limit: Maximum results to return (default 1000)
1037
+ cursor: Pagination cursor from previous response's next_cursor
1038
+ fields: Field paths to include in results. Each path is a list of keys for nested access.
1039
+ Example: [["id"], ["user", "name"]] returns id and user.name fields.
1040
+
1041
+ Returns:
1042
+ DepartmentsSearchResult with hits (list of AirbyteSearchHit[DepartmentsSearchData]) and pagination info
1043
+
1044
+ Raises:
1045
+ NotImplementedError: If called in local execution mode
1046
+ """
1047
+ params: dict[str, Any] = {"query": query}
1048
+ if limit is not None:
1049
+ params["limit"] = limit
1050
+ if cursor is not None:
1051
+ params["cursor"] = cursor
1052
+ if fields is not None:
1053
+ params["fields"] = fields
1054
+
1055
+ result = await self._connector.execute("departments", "search", params)
1056
+
1057
+ # Parse response into typed result
1058
+ return DepartmentsSearchResult(
1059
+ hits=[
1060
+ AirbyteSearchHit[DepartmentsSearchData](
1061
+ id=hit.get("id"),
1062
+ score=hit.get("score"),
1063
+ data=DepartmentsSearchData(**hit.get("data", {}))
1064
+ )
1065
+ for hit in result.get("hits", [])
1066
+ ],
1067
+ next_cursor=result.get("next_cursor"),
1068
+ took_ms=result.get("took_ms")
1069
+ )
1070
+
1071
+ class GoalsQuery:
1072
+ """
1073
+ Query class for Goals entity operations.
1074
+ """
1075
+
1076
+ def __init__(self, connector: ZendeskChatConnector):
1077
+ """Initialize query with connector reference."""
1078
+ self._connector = connector
1079
+
1080
+ async def list(
1081
+ self,
1082
+ **kwargs
1083
+ ) -> GoalsListResult:
1084
+ """
1085
+ List all goals
1086
+
1087
+ Returns:
1088
+ GoalsListResult
1089
+ """
1090
+ params = {k: v for k, v in {
1091
+ **kwargs
1092
+ }.items() if v is not None}
1093
+
1094
+ result = await self._connector.execute("goals", "list", params)
1095
+ # Cast generic envelope to concrete typed result
1096
+ return GoalsListResult(
1097
+ data=result.data
1098
+ )
1099
+
1100
+
1101
+
1102
+ async def get(
1103
+ self,
1104
+ goal_id: str,
1105
+ **kwargs
1106
+ ) -> Goal:
1107
+ """
1108
+ Get a goal
1109
+
1110
+ Args:
1111
+ goal_id: Parameter goal_id
1112
+ **kwargs: Additional parameters
1113
+
1114
+ Returns:
1115
+ Goal
1116
+ """
1117
+ params = {k: v for k, v in {
1118
+ "goal_id": goal_id,
1119
+ **kwargs
1120
+ }.items() if v is not None}
1121
+
1122
+ result = await self._connector.execute("goals", "get", params)
1123
+ return result
1124
+
1125
+
1126
+
1127
+ class RolesQuery:
1128
+ """
1129
+ Query class for Roles entity operations.
1130
+ """
1131
+
1132
+ def __init__(self, connector: ZendeskChatConnector):
1133
+ """Initialize query with connector reference."""
1134
+ self._connector = connector
1135
+
1136
+ async def list(
1137
+ self,
1138
+ **kwargs
1139
+ ) -> RolesListResult:
1140
+ """
1141
+ List all roles
1142
+
1143
+ Returns:
1144
+ RolesListResult
1145
+ """
1146
+ params = {k: v for k, v in {
1147
+ **kwargs
1148
+ }.items() if v is not None}
1149
+
1150
+ result = await self._connector.execute("roles", "list", params)
1151
+ # Cast generic envelope to concrete typed result
1152
+ return RolesListResult(
1153
+ data=result.data
1154
+ )
1155
+
1156
+
1157
+
1158
+ async def get(
1159
+ self,
1160
+ role_id: str,
1161
+ **kwargs
1162
+ ) -> Role:
1163
+ """
1164
+ Get a role
1165
+
1166
+ Args:
1167
+ role_id: Parameter role_id
1168
+ **kwargs: Additional parameters
1169
+
1170
+ Returns:
1171
+ Role
1172
+ """
1173
+ params = {k: v for k, v in {
1174
+ "role_id": role_id,
1175
+ **kwargs
1176
+ }.items() if v is not None}
1177
+
1178
+ result = await self._connector.execute("roles", "get", params)
1179
+ return result
1180
+
1181
+
1182
+
1183
+ class RoutingSettingsQuery:
1184
+ """
1185
+ Query class for RoutingSettings entity operations.
1186
+ """
1187
+
1188
+ def __init__(self, connector: ZendeskChatConnector):
1189
+ """Initialize query with connector reference."""
1190
+ self._connector = connector
1191
+
1192
+ async def get(
1193
+ self,
1194
+ **kwargs
1195
+ ) -> RoutingSettings:
1196
+ """
1197
+ Get routing settings
1198
+
1199
+ Returns:
1200
+ RoutingSettings
1201
+ """
1202
+ params = {k: v for k, v in {
1203
+ **kwargs
1204
+ }.items() if v is not None}
1205
+
1206
+ result = await self._connector.execute("routing_settings", "get", params)
1207
+ return result
1208
+
1209
+
1210
+
1211
+ class ShortcutsQuery:
1212
+ """
1213
+ Query class for Shortcuts entity operations.
1214
+ """
1215
+
1216
+ def __init__(self, connector: ZendeskChatConnector):
1217
+ """Initialize query with connector reference."""
1218
+ self._connector = connector
1219
+
1220
+ async def list(
1221
+ self,
1222
+ **kwargs
1223
+ ) -> ShortcutsListResult:
1224
+ """
1225
+ List all shortcuts
1226
+
1227
+ Returns:
1228
+ ShortcutsListResult
1229
+ """
1230
+ params = {k: v for k, v in {
1231
+ **kwargs
1232
+ }.items() if v is not None}
1233
+
1234
+ result = await self._connector.execute("shortcuts", "list", params)
1235
+ # Cast generic envelope to concrete typed result
1236
+ return ShortcutsListResult(
1237
+ data=result.data
1238
+ )
1239
+
1240
+
1241
+
1242
+ async def get(
1243
+ self,
1244
+ shortcut_id: str,
1245
+ **kwargs
1246
+ ) -> Shortcut:
1247
+ """
1248
+ Get a shortcut
1249
+
1250
+ Args:
1251
+ shortcut_id: Parameter shortcut_id
1252
+ **kwargs: Additional parameters
1253
+
1254
+ Returns:
1255
+ Shortcut
1256
+ """
1257
+ params = {k: v for k, v in {
1258
+ "shortcut_id": shortcut_id,
1259
+ **kwargs
1260
+ }.items() if v is not None}
1261
+
1262
+ result = await self._connector.execute("shortcuts", "get", params)
1263
+ return result
1264
+
1265
+
1266
+
1267
+ async def search(
1268
+ self,
1269
+ query: ShortcutsSearchQuery,
1270
+ limit: int | None = None,
1271
+ cursor: str | None = None,
1272
+ fields: list[list[str]] | None = None,
1273
+ ) -> ShortcutsSearchResult:
1274
+ """
1275
+ Search shortcuts records from Airbyte cache.
1276
+
1277
+ This operation searches cached data from Airbyte syncs.
1278
+ Only available in hosted execution mode.
1279
+
1280
+ Available filter fields (ShortcutsSearchFilter):
1281
+ - id: Shortcut ID
1282
+ - name: Shortcut name/trigger
1283
+ - message: Shortcut message content
1284
+ - tags: Tags applied when shortcut is used
1285
+
1286
+ Args:
1287
+ query: Filter and sort conditions. Supports operators like eq, neq, gt, gte, lt, lte,
1288
+ in, like, fuzzy, keyword, not, and, or. Example: {"filter": {"eq": {"status": "active"}}}
1289
+ limit: Maximum results to return (default 1000)
1290
+ cursor: Pagination cursor from previous response's next_cursor
1291
+ fields: Field paths to include in results. Each path is a list of keys for nested access.
1292
+ Example: [["id"], ["user", "name"]] returns id and user.name fields.
1293
+
1294
+ Returns:
1295
+ ShortcutsSearchResult with hits (list of AirbyteSearchHit[ShortcutsSearchData]) and pagination info
1296
+
1297
+ Raises:
1298
+ NotImplementedError: If called in local execution mode
1299
+ """
1300
+ params: dict[str, Any] = {"query": query}
1301
+ if limit is not None:
1302
+ params["limit"] = limit
1303
+ if cursor is not None:
1304
+ params["cursor"] = cursor
1305
+ if fields is not None:
1306
+ params["fields"] = fields
1307
+
1308
+ result = await self._connector.execute("shortcuts", "search", params)
1309
+
1310
+ # Parse response into typed result
1311
+ return ShortcutsSearchResult(
1312
+ hits=[
1313
+ AirbyteSearchHit[ShortcutsSearchData](
1314
+ id=hit.get("id"),
1315
+ score=hit.get("score"),
1316
+ data=ShortcutsSearchData(**hit.get("data", {}))
1317
+ )
1318
+ for hit in result.get("hits", [])
1319
+ ],
1320
+ next_cursor=result.get("next_cursor"),
1321
+ took_ms=result.get("took_ms")
1322
+ )
1323
+
1324
+ class SkillsQuery:
1325
+ """
1326
+ Query class for Skills entity operations.
1327
+ """
1328
+
1329
+ def __init__(self, connector: ZendeskChatConnector):
1330
+ """Initialize query with connector reference."""
1331
+ self._connector = connector
1332
+
1333
+ async def list(
1334
+ self,
1335
+ **kwargs
1336
+ ) -> SkillsListResult:
1337
+ """
1338
+ List all skills
1339
+
1340
+ Returns:
1341
+ SkillsListResult
1342
+ """
1343
+ params = {k: v for k, v in {
1344
+ **kwargs
1345
+ }.items() if v is not None}
1346
+
1347
+ result = await self._connector.execute("skills", "list", params)
1348
+ # Cast generic envelope to concrete typed result
1349
+ return SkillsListResult(
1350
+ data=result.data
1351
+ )
1352
+
1353
+
1354
+
1355
+ async def get(
1356
+ self,
1357
+ skill_id: str,
1358
+ **kwargs
1359
+ ) -> Skill:
1360
+ """
1361
+ Get a skill
1362
+
1363
+ Args:
1364
+ skill_id: Parameter skill_id
1365
+ **kwargs: Additional parameters
1366
+
1367
+ Returns:
1368
+ Skill
1369
+ """
1370
+ params = {k: v for k, v in {
1371
+ "skill_id": skill_id,
1372
+ **kwargs
1373
+ }.items() if v is not None}
1374
+
1375
+ result = await self._connector.execute("skills", "get", params)
1376
+ return result
1377
+
1378
+
1379
+
1380
+ class TriggersQuery:
1381
+ """
1382
+ Query class for Triggers entity operations.
1383
+ """
1384
+
1385
+ def __init__(self, connector: ZendeskChatConnector):
1386
+ """Initialize query with connector reference."""
1387
+ self._connector = connector
1388
+
1389
+ async def list(
1390
+ self,
1391
+ **kwargs
1392
+ ) -> TriggersListResult:
1393
+ """
1394
+ List all triggers
1395
+
1396
+ Returns:
1397
+ TriggersListResult
1398
+ """
1399
+ params = {k: v for k, v in {
1400
+ **kwargs
1401
+ }.items() if v is not None}
1402
+
1403
+ result = await self._connector.execute("triggers", "list", params)
1404
+ # Cast generic envelope to concrete typed result
1405
+ return TriggersListResult(
1406
+ data=result.data
1407
+ )
1408
+
1409
+
1410
+
1411
+ async def search(
1412
+ self,
1413
+ query: TriggersSearchQuery,
1414
+ limit: int | None = None,
1415
+ cursor: str | None = None,
1416
+ fields: list[list[str]] | None = None,
1417
+ ) -> TriggersSearchResult:
1418
+ """
1419
+ Search triggers records from Airbyte cache.
1420
+
1421
+ This operation searches cached data from Airbyte syncs.
1422
+ Only available in hosted execution mode.
1423
+
1424
+ Available filter fields (TriggersSearchFilter):
1425
+ - id: Trigger ID
1426
+ - name: Trigger name
1427
+ - enabled: Whether trigger is enabled
1428
+
1429
+ Args:
1430
+ query: Filter and sort conditions. Supports operators like eq, neq, gt, gte, lt, lte,
1431
+ in, like, fuzzy, keyword, not, and, or. Example: {"filter": {"eq": {"status": "active"}}}
1432
+ limit: Maximum results to return (default 1000)
1433
+ cursor: Pagination cursor from previous response's next_cursor
1434
+ fields: Field paths to include in results. Each path is a list of keys for nested access.
1435
+ Example: [["id"], ["user", "name"]] returns id and user.name fields.
1436
+
1437
+ Returns:
1438
+ TriggersSearchResult with hits (list of AirbyteSearchHit[TriggersSearchData]) and pagination info
1439
+
1440
+ Raises:
1441
+ NotImplementedError: If called in local execution mode
1442
+ """
1443
+ params: dict[str, Any] = {"query": query}
1444
+ if limit is not None:
1445
+ params["limit"] = limit
1446
+ if cursor is not None:
1447
+ params["cursor"] = cursor
1448
+ if fields is not None:
1449
+ params["fields"] = fields
1450
+
1451
+ result = await self._connector.execute("triggers", "search", params)
1452
+
1453
+ # Parse response into typed result
1454
+ return TriggersSearchResult(
1455
+ hits=[
1456
+ AirbyteSearchHit[TriggersSearchData](
1457
+ id=hit.get("id"),
1458
+ score=hit.get("score"),
1459
+ data=TriggersSearchData(**hit.get("data", {}))
1460
+ )
1461
+ for hit in result.get("hits", [])
1462
+ ],
1463
+ next_cursor=result.get("next_cursor"),
1464
+ took_ms=result.get("took_ms")
1465
+ )