airbyte-agent-slack 0.1.0__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.
Files changed (57) hide show
  1. airbyte_agent_slack/__init__.py +87 -0
  2. airbyte_agent_slack/_vendored/__init__.py +1 -0
  3. airbyte_agent_slack/_vendored/connector_sdk/__init__.py +82 -0
  4. airbyte_agent_slack/_vendored/connector_sdk/auth_strategies.py +1120 -0
  5. airbyte_agent_slack/_vendored/connector_sdk/auth_template.py +135 -0
  6. airbyte_agent_slack/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
  7. airbyte_agent_slack/_vendored/connector_sdk/cloud_utils/client.py +213 -0
  8. airbyte_agent_slack/_vendored/connector_sdk/connector_model_loader.py +964 -0
  9. airbyte_agent_slack/_vendored/connector_sdk/constants.py +78 -0
  10. airbyte_agent_slack/_vendored/connector_sdk/exceptions.py +23 -0
  11. airbyte_agent_slack/_vendored/connector_sdk/executor/__init__.py +31 -0
  12. airbyte_agent_slack/_vendored/connector_sdk/executor/hosted_executor.py +196 -0
  13. airbyte_agent_slack/_vendored/connector_sdk/executor/local_executor.py +1633 -0
  14. airbyte_agent_slack/_vendored/connector_sdk/executor/models.py +190 -0
  15. airbyte_agent_slack/_vendored/connector_sdk/extensions.py +693 -0
  16. airbyte_agent_slack/_vendored/connector_sdk/http/__init__.py +37 -0
  17. airbyte_agent_slack/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
  18. airbyte_agent_slack/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
  19. airbyte_agent_slack/_vendored/connector_sdk/http/config.py +98 -0
  20. airbyte_agent_slack/_vendored/connector_sdk/http/exceptions.py +119 -0
  21. airbyte_agent_slack/_vendored/connector_sdk/http/protocols.py +114 -0
  22. airbyte_agent_slack/_vendored/connector_sdk/http/response.py +104 -0
  23. airbyte_agent_slack/_vendored/connector_sdk/http_client.py +686 -0
  24. airbyte_agent_slack/_vendored/connector_sdk/introspection.py +262 -0
  25. airbyte_agent_slack/_vendored/connector_sdk/logging/__init__.py +11 -0
  26. airbyte_agent_slack/_vendored/connector_sdk/logging/logger.py +264 -0
  27. airbyte_agent_slack/_vendored/connector_sdk/logging/types.py +92 -0
  28. airbyte_agent_slack/_vendored/connector_sdk/observability/__init__.py +11 -0
  29. airbyte_agent_slack/_vendored/connector_sdk/observability/config.py +179 -0
  30. airbyte_agent_slack/_vendored/connector_sdk/observability/models.py +19 -0
  31. airbyte_agent_slack/_vendored/connector_sdk/observability/redactor.py +81 -0
  32. airbyte_agent_slack/_vendored/connector_sdk/observability/session.py +103 -0
  33. airbyte_agent_slack/_vendored/connector_sdk/performance/__init__.py +6 -0
  34. airbyte_agent_slack/_vendored/connector_sdk/performance/instrumentation.py +57 -0
  35. airbyte_agent_slack/_vendored/connector_sdk/performance/metrics.py +93 -0
  36. airbyte_agent_slack/_vendored/connector_sdk/schema/__init__.py +75 -0
  37. airbyte_agent_slack/_vendored/connector_sdk/schema/base.py +161 -0
  38. airbyte_agent_slack/_vendored/connector_sdk/schema/components.py +239 -0
  39. airbyte_agent_slack/_vendored/connector_sdk/schema/connector.py +120 -0
  40. airbyte_agent_slack/_vendored/connector_sdk/schema/extensions.py +109 -0
  41. airbyte_agent_slack/_vendored/connector_sdk/schema/operations.py +146 -0
  42. airbyte_agent_slack/_vendored/connector_sdk/schema/security.py +223 -0
  43. airbyte_agent_slack/_vendored/connector_sdk/secrets.py +182 -0
  44. airbyte_agent_slack/_vendored/connector_sdk/telemetry/__init__.py +10 -0
  45. airbyte_agent_slack/_vendored/connector_sdk/telemetry/config.py +32 -0
  46. airbyte_agent_slack/_vendored/connector_sdk/telemetry/events.py +59 -0
  47. airbyte_agent_slack/_vendored/connector_sdk/telemetry/tracker.py +155 -0
  48. airbyte_agent_slack/_vendored/connector_sdk/types.py +245 -0
  49. airbyte_agent_slack/_vendored/connector_sdk/utils.py +60 -0
  50. airbyte_agent_slack/_vendored/connector_sdk/validation.py +822 -0
  51. airbyte_agent_slack/connector.py +620 -0
  52. airbyte_agent_slack/connector_model.py +2124 -0
  53. airbyte_agent_slack/models.py +394 -0
  54. airbyte_agent_slack/types.py +56 -0
  55. airbyte_agent_slack-0.1.0.dist-info/METADATA +128 -0
  56. airbyte_agent_slack-0.1.0.dist-info/RECORD +57 -0
  57. airbyte_agent_slack-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,620 @@
1
+ """
2
+ Slack 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 SlackConnectorModel
15
+ from ._vendored.connector_sdk.introspection import describe_entities, generate_tool_description
16
+ from .types import (
17
+ ChannelMessagesListParams,
18
+ ChannelsGetParams,
19
+ ChannelsListParams,
20
+ ThreadsListParams,
21
+ UsersGetParams,
22
+ UsersListParams,
23
+ )
24
+ if TYPE_CHECKING:
25
+ from .models import SlackAuthConfig
26
+ # Import specific auth config classes for multi-auth isinstance checks
27
+ from .models import SlackTokenAuthenticationAuthConfig, SlackOauth20AuthenticationAuthConfig
28
+ # Import response models and envelope models at runtime
29
+ from .models import (
30
+ SlackExecuteResult,
31
+ SlackExecuteResultWithMeta,
32
+ UsersListResult,
33
+ ChannelsListResult,
34
+ ChannelMessagesListResult,
35
+ ThreadsListResult,
36
+ Channel,
37
+ Message,
38
+ Thread,
39
+ User,
40
+ )
41
+
42
+ # TypeVar for decorator type preservation
43
+ _F = TypeVar("_F", bound=Callable[..., Any])
44
+
45
+
46
+ class SlackConnector:
47
+ """
48
+ Type-safe Slack API connector.
49
+
50
+ Auto-generated from OpenAPI specification with full type safety.
51
+ """
52
+
53
+ connector_name = "slack"
54
+ connector_version = "0.1.1"
55
+ vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
56
+
57
+ # Map of (entity, action) -> needs_envelope for envelope wrapping decision
58
+ _ENVELOPE_MAP = {
59
+ ("users", "list"): True,
60
+ ("users", "get"): None,
61
+ ("channels", "list"): True,
62
+ ("channels", "get"): None,
63
+ ("channel_messages", "list"): True,
64
+ ("threads", "list"): True,
65
+ }
66
+
67
+ # Map of (entity, action) -> {python_param_name: api_param_name}
68
+ # Used to convert snake_case TypedDict keys to API parameter names in execute()
69
+ _PARAM_MAP = {
70
+ ('users', 'list'): {'cursor': 'cursor', 'limit': 'limit'},
71
+ ('users', 'get'): {'user': 'user'},
72
+ ('channels', 'list'): {'cursor': 'cursor', 'limit': 'limit', 'types': 'types', 'exclude_archived': 'exclude_archived'},
73
+ ('channels', 'get'): {'channel': 'channel'},
74
+ ('channel_messages', 'list'): {'channel': 'channel', 'cursor': 'cursor', 'limit': 'limit', 'oldest': 'oldest', 'latest': 'latest', 'inclusive': 'inclusive'},
75
+ ('threads', 'list'): {'channel': 'channel', 'ts': 'ts', 'cursor': 'cursor', 'limit': 'limit', 'oldest': 'oldest', 'latest': 'latest', 'inclusive': 'inclusive'},
76
+ }
77
+
78
+ def __init__(
79
+ self,
80
+ auth_config: SlackAuthConfig | None = None,
81
+ external_user_id: str | None = None,
82
+ airbyte_client_id: str | None = None,
83
+ airbyte_client_secret: str | None = None,
84
+ on_token_refresh: Any | None = None ):
85
+ """
86
+ Initialize a new slack connector instance.
87
+
88
+ Supports both local and hosted execution modes:
89
+ - Local mode: Provide `auth_config` for direct API calls
90
+ - Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
91
+
92
+ Args:
93
+ auth_config: Typed authentication configuration (required for local mode)
94
+ external_user_id: External user ID (required for hosted mode)
95
+ airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
96
+ airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
97
+ on_token_refresh: Optional callback for OAuth2 token refresh persistence.
98
+ Called with new_tokens dict when tokens are refreshed. Can be sync or async.
99
+ Example: lambda tokens: save_to_database(tokens)
100
+ Examples:
101
+ # Local mode (direct API calls)
102
+ connector = SlackConnector(auth_config=SlackAuthConfig(access_token="..."))
103
+ # Hosted mode (executed on Airbyte cloud)
104
+ connector = SlackConnector(
105
+ external_user_id="user-123",
106
+ airbyte_client_id="client_abc123",
107
+ airbyte_client_secret="secret_xyz789"
108
+ )
109
+
110
+ # Local mode with OAuth2 token refresh callback
111
+ def save_tokens(new_tokens: dict) -> None:
112
+ # Persist updated tokens to your storage (file, database, etc.)
113
+ with open("tokens.json", "w") as f:
114
+ json.dump(new_tokens, f)
115
+
116
+ connector = SlackConnector(
117
+ auth_config=SlackAuthConfig(access_token="...", refresh_token="..."),
118
+ on_token_refresh=save_tokens
119
+ )
120
+ """
121
+ # Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
122
+ if external_user_id and airbyte_client_id and airbyte_client_secret:
123
+ from ._vendored.connector_sdk.executor import HostedExecutor
124
+ self._executor = HostedExecutor(
125
+ external_user_id=external_user_id,
126
+ airbyte_client_id=airbyte_client_id,
127
+ airbyte_client_secret=airbyte_client_secret,
128
+ connector_definition_id=str(SlackConnectorModel.id),
129
+ )
130
+ else:
131
+ # Local mode: auth_config required
132
+ if not auth_config:
133
+ raise ValueError(
134
+ "Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
135
+ "or auth_config for local mode"
136
+ )
137
+
138
+ from ._vendored.connector_sdk.executor import LocalExecutor
139
+
140
+ # Build config_values dict from server variables
141
+ config_values = None
142
+
143
+ # Multi-auth connector: detect auth scheme from auth_config type
144
+ auth_scheme: str | None = None
145
+ if auth_config:
146
+ if isinstance(auth_config, SlackTokenAuthenticationAuthConfig):
147
+ auth_scheme = "bearerAuth"
148
+ if isinstance(auth_config, SlackOauth20AuthenticationAuthConfig):
149
+ auth_scheme = "oauth2"
150
+
151
+ self._executor = LocalExecutor(
152
+ model=SlackConnectorModel,
153
+ auth_config=auth_config.model_dump() if auth_config else None,
154
+ auth_scheme=auth_scheme,
155
+ config_values=config_values,
156
+ on_token_refresh=on_token_refresh
157
+ )
158
+
159
+ # Update base_url with server variables if provided
160
+
161
+ # Initialize entity query objects
162
+ self.users = UsersQuery(self)
163
+ self.channels = ChannelsQuery(self)
164
+ self.channel_messages = ChannelMessagesQuery(self)
165
+ self.threads = ThreadsQuery(self)
166
+
167
+ # ===== TYPED EXECUTE METHOD (Recommended Interface) =====
168
+
169
+ @overload
170
+ async def execute(
171
+ self,
172
+ entity: Literal["users"],
173
+ action: Literal["list"],
174
+ params: "UsersListParams"
175
+ ) -> "UsersListResult": ...
176
+
177
+ @overload
178
+ async def execute(
179
+ self,
180
+ entity: Literal["users"],
181
+ action: Literal["get"],
182
+ params: "UsersGetParams"
183
+ ) -> "User": ...
184
+
185
+ @overload
186
+ async def execute(
187
+ self,
188
+ entity: Literal["channels"],
189
+ action: Literal["list"],
190
+ params: "ChannelsListParams"
191
+ ) -> "ChannelsListResult": ...
192
+
193
+ @overload
194
+ async def execute(
195
+ self,
196
+ entity: Literal["channels"],
197
+ action: Literal["get"],
198
+ params: "ChannelsGetParams"
199
+ ) -> "Channel": ...
200
+
201
+ @overload
202
+ async def execute(
203
+ self,
204
+ entity: Literal["channel_messages"],
205
+ action: Literal["list"],
206
+ params: "ChannelMessagesListParams"
207
+ ) -> "ChannelMessagesListResult": ...
208
+
209
+ @overload
210
+ async def execute(
211
+ self,
212
+ entity: Literal["threads"],
213
+ action: Literal["list"],
214
+ params: "ThreadsListParams"
215
+ ) -> "ThreadsListResult": ...
216
+
217
+
218
+ @overload
219
+ async def execute(
220
+ self,
221
+ entity: str,
222
+ action: str,
223
+ params: dict[str, Any]
224
+ ) -> SlackExecuteResult[Any] | SlackExecuteResultWithMeta[Any, Any] | Any: ...
225
+
226
+ async def execute(
227
+ self,
228
+ entity: str,
229
+ action: str,
230
+ params: dict[str, Any] | None = None
231
+ ) -> Any:
232
+ """
233
+ Execute an entity operation with full type safety.
234
+
235
+ This is the recommended interface for blessed connectors as it:
236
+ - Uses the same signature as non-blessed connectors
237
+ - Provides full IDE autocomplete for entity/action/params
238
+ - Makes migration from generic to blessed connectors seamless
239
+
240
+ Args:
241
+ entity: Entity name (e.g., "customers")
242
+ action: Operation action (e.g., "create", "get", "list")
243
+ params: Operation parameters (typed based on entity+action)
244
+
245
+ Returns:
246
+ Typed response based on the operation
247
+
248
+ Example:
249
+ customer = await connector.execute(
250
+ entity="customers",
251
+ action="get",
252
+ params={"id": "cus_123"}
253
+ )
254
+ """
255
+ from ._vendored.connector_sdk.executor import ExecutionConfig
256
+
257
+ # Remap parameter names from snake_case (TypedDict keys) to API parameter names
258
+ if params:
259
+ param_map = self._PARAM_MAP.get((entity, action), {})
260
+ if param_map:
261
+ params = {param_map.get(k, k): v for k, v in params.items()}
262
+
263
+ # Use ExecutionConfig for both local and hosted executors
264
+ config = ExecutionConfig(
265
+ entity=entity,
266
+ action=action,
267
+ params=params
268
+ )
269
+
270
+ result = await self._executor.execute(config)
271
+
272
+ if not result.success:
273
+ raise RuntimeError(f"Execution failed: {result.error}")
274
+
275
+ # Check if this operation has extractors configured
276
+ has_extractors = self._ENVELOPE_MAP.get((entity, action), False)
277
+
278
+ if has_extractors:
279
+ # With extractors - return Pydantic envelope with data and meta
280
+ if result.meta is not None:
281
+ return SlackExecuteResultWithMeta[Any, Any](
282
+ data=result.data,
283
+ meta=result.meta
284
+ )
285
+ else:
286
+ return SlackExecuteResult[Any](data=result.data)
287
+ else:
288
+ # No extractors - return raw response data
289
+ return result.data
290
+
291
+ # ===== INTROSPECTION METHODS =====
292
+
293
+ @classmethod
294
+ def describe(cls, func: _F) -> _F:
295
+ """
296
+ Decorator that populates a function's docstring with connector capabilities.
297
+
298
+ This class method can be used as a decorator to automatically generate
299
+ comprehensive documentation for AI tool functions.
300
+
301
+ Usage:
302
+ @mcp.tool()
303
+ @SlackConnector.describe
304
+ async def execute(entity: str, action: str, params: dict):
305
+ '''Execute operations.'''
306
+ ...
307
+
308
+ The decorated function's __doc__ will be updated with:
309
+ - Available entities and their actions
310
+ - Parameter signatures with required (*) and optional (?) markers
311
+ - Response structure documentation
312
+ - Example questions (if available in OpenAPI spec)
313
+
314
+ Args:
315
+ func: The function to decorate
316
+
317
+ Returns:
318
+ The same function with updated __doc__
319
+ """
320
+ description = generate_tool_description(SlackConnectorModel)
321
+
322
+ original_doc = func.__doc__ or ""
323
+ if original_doc.strip():
324
+ func.__doc__ = f"{original_doc.strip()}\n{description}"
325
+ else:
326
+ func.__doc__ = description
327
+
328
+ return func
329
+
330
+ def list_entities(self) -> list[dict[str, Any]]:
331
+ """
332
+ Get structured data about available entities, actions, and parameters.
333
+
334
+ Returns a list of entity descriptions with:
335
+ - entity_name: Name of the entity (e.g., "contacts", "deals")
336
+ - description: Entity description from the first endpoint
337
+ - available_actions: List of actions (e.g., ["list", "get", "create"])
338
+ - parameters: Dict mapping action -> list of parameter dicts
339
+
340
+ Example:
341
+ entities = connector.list_entities()
342
+ for entity in entities:
343
+ print(f"{entity['entity_name']}: {entity['available_actions']}")
344
+ """
345
+ return describe_entities(SlackConnectorModel)
346
+
347
+ def entity_schema(self, entity: str) -> dict[str, Any] | None:
348
+ """
349
+ Get the JSON schema for an entity.
350
+
351
+ Args:
352
+ entity: Entity name (e.g., "contacts", "companies")
353
+
354
+ Returns:
355
+ JSON schema dict describing the entity structure, or None if not found.
356
+
357
+ Example:
358
+ schema = connector.entity_schema("contacts")
359
+ if schema:
360
+ print(f"Contact properties: {list(schema.get('properties', {}).keys())}")
361
+ """
362
+ entity_def = next(
363
+ (e for e in SlackConnectorModel.entities if e.name == entity),
364
+ None
365
+ )
366
+ if entity_def is None:
367
+ logging.getLogger(__name__).warning(
368
+ f"Entity '{entity}' not found. Available entities: "
369
+ f"{[e.name for e in SlackConnectorModel.entities]}"
370
+ )
371
+ return entity_def.entity_schema if entity_def else None
372
+
373
+
374
+
375
+ class UsersQuery:
376
+ """
377
+ Query class for Users entity operations.
378
+ """
379
+
380
+ def __init__(self, connector: SlackConnector):
381
+ """Initialize query with connector reference."""
382
+ self._connector = connector
383
+
384
+ async def list(
385
+ self,
386
+ cursor: str | None = None,
387
+ limit: int | None = None,
388
+ **kwargs
389
+ ) -> UsersListResult:
390
+ """
391
+ Returns a list of all users in the Slack workspace
392
+
393
+ Args:
394
+ cursor: Pagination cursor for next page
395
+ limit: Number of users to return per page
396
+ **kwargs: Additional parameters
397
+
398
+ Returns:
399
+ UsersListResult
400
+ """
401
+ params = {k: v for k, v in {
402
+ "cursor": cursor,
403
+ "limit": limit,
404
+ **kwargs
405
+ }.items() if v is not None}
406
+
407
+ result = await self._connector.execute("users", "list", params)
408
+ # Cast generic envelope to concrete typed result
409
+ return UsersListResult(
410
+ data=result.data,
411
+ meta=result.meta
412
+ )
413
+
414
+
415
+
416
+ async def get(
417
+ self,
418
+ user: str,
419
+ **kwargs
420
+ ) -> User:
421
+ """
422
+ Get information about a single user by ID
423
+
424
+ Args:
425
+ user: User ID
426
+ **kwargs: Additional parameters
427
+
428
+ Returns:
429
+ User
430
+ """
431
+ params = {k: v for k, v in {
432
+ "user": user,
433
+ **kwargs
434
+ }.items() if v is not None}
435
+
436
+ result = await self._connector.execute("users", "get", params)
437
+ return result
438
+
439
+
440
+
441
+ class ChannelsQuery:
442
+ """
443
+ Query class for Channels entity operations.
444
+ """
445
+
446
+ def __init__(self, connector: SlackConnector):
447
+ """Initialize query with connector reference."""
448
+ self._connector = connector
449
+
450
+ async def list(
451
+ self,
452
+ cursor: str | None = None,
453
+ limit: int | None = None,
454
+ types: str | None = None,
455
+ exclude_archived: bool | None = None,
456
+ **kwargs
457
+ ) -> ChannelsListResult:
458
+ """
459
+ Returns a list of all channels in the Slack workspace
460
+
461
+ Args:
462
+ cursor: Pagination cursor for next page
463
+ limit: Number of channels to return per page
464
+ types: Mix and match channel types (public_channel, private_channel, mpim, im)
465
+ exclude_archived: Exclude archived channels
466
+ **kwargs: Additional parameters
467
+
468
+ Returns:
469
+ ChannelsListResult
470
+ """
471
+ params = {k: v for k, v in {
472
+ "cursor": cursor,
473
+ "limit": limit,
474
+ "types": types,
475
+ "exclude_archived": exclude_archived,
476
+ **kwargs
477
+ }.items() if v is not None}
478
+
479
+ result = await self._connector.execute("channels", "list", params)
480
+ # Cast generic envelope to concrete typed result
481
+ return ChannelsListResult(
482
+ data=result.data,
483
+ meta=result.meta
484
+ )
485
+
486
+
487
+
488
+ async def get(
489
+ self,
490
+ channel: str,
491
+ **kwargs
492
+ ) -> Channel:
493
+ """
494
+ Get information about a single channel by ID
495
+
496
+ Args:
497
+ channel: Channel ID
498
+ **kwargs: Additional parameters
499
+
500
+ Returns:
501
+ Channel
502
+ """
503
+ params = {k: v for k, v in {
504
+ "channel": channel,
505
+ **kwargs
506
+ }.items() if v is not None}
507
+
508
+ result = await self._connector.execute("channels", "get", params)
509
+ return result
510
+
511
+
512
+
513
+ class ChannelMessagesQuery:
514
+ """
515
+ Query class for ChannelMessages entity operations.
516
+ """
517
+
518
+ def __init__(self, connector: SlackConnector):
519
+ """Initialize query with connector reference."""
520
+ self._connector = connector
521
+
522
+ async def list(
523
+ self,
524
+ channel: str,
525
+ cursor: str | None = None,
526
+ limit: int | None = None,
527
+ oldest: str | None = None,
528
+ latest: str | None = None,
529
+ inclusive: bool | None = None,
530
+ **kwargs
531
+ ) -> ChannelMessagesListResult:
532
+ """
533
+ Returns messages from a channel
534
+
535
+ Args:
536
+ channel: Channel ID to get messages from
537
+ cursor: Pagination cursor for next page
538
+ limit: Number of messages to return per page
539
+ oldest: Start of time range (Unix timestamp)
540
+ latest: End of time range (Unix timestamp)
541
+ inclusive: Include messages with oldest or latest timestamps
542
+ **kwargs: Additional parameters
543
+
544
+ Returns:
545
+ ChannelMessagesListResult
546
+ """
547
+ params = {k: v for k, v in {
548
+ "channel": channel,
549
+ "cursor": cursor,
550
+ "limit": limit,
551
+ "oldest": oldest,
552
+ "latest": latest,
553
+ "inclusive": inclusive,
554
+ **kwargs
555
+ }.items() if v is not None}
556
+
557
+ result = await self._connector.execute("channel_messages", "list", params)
558
+ # Cast generic envelope to concrete typed result
559
+ return ChannelMessagesListResult(
560
+ data=result.data,
561
+ meta=result.meta
562
+ )
563
+
564
+
565
+
566
+ class ThreadsQuery:
567
+ """
568
+ Query class for Threads entity operations.
569
+ """
570
+
571
+ def __init__(self, connector: SlackConnector):
572
+ """Initialize query with connector reference."""
573
+ self._connector = connector
574
+
575
+ async def list(
576
+ self,
577
+ channel: str,
578
+ ts: str | None = None,
579
+ cursor: str | None = None,
580
+ limit: int | None = None,
581
+ oldest: str | None = None,
582
+ latest: str | None = None,
583
+ inclusive: bool | None = None,
584
+ **kwargs
585
+ ) -> ThreadsListResult:
586
+ """
587
+ Returns messages in a thread (thread replies from conversations.replies endpoint)
588
+
589
+ Args:
590
+ channel: Channel ID containing the thread
591
+ ts: Timestamp of the parent message (required for thread replies)
592
+ cursor: Pagination cursor for next page
593
+ limit: Number of replies to return per page
594
+ oldest: Start of time range (Unix timestamp)
595
+ latest: End of time range (Unix timestamp)
596
+ inclusive: Include messages with oldest or latest timestamps
597
+ **kwargs: Additional parameters
598
+
599
+ Returns:
600
+ ThreadsListResult
601
+ """
602
+ params = {k: v for k, v in {
603
+ "channel": channel,
604
+ "ts": ts,
605
+ "cursor": cursor,
606
+ "limit": limit,
607
+ "oldest": oldest,
608
+ "latest": latest,
609
+ "inclusive": inclusive,
610
+ **kwargs
611
+ }.items() if v is not None}
612
+
613
+ result = await self._connector.execute("threads", "list", params)
614
+ # Cast generic envelope to concrete typed result
615
+ return ThreadsListResult(
616
+ data=result.data,
617
+ meta=result.meta
618
+ )
619
+
620
+