telnyx-mcp-server-fastmcp 0.1.3__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.
- telnyx_mcp_server/__init__.py +0 -0
- telnyx_mcp_server/__main__.py +23 -0
- telnyx_mcp_server/config.py +148 -0
- telnyx_mcp_server/mcp.py +148 -0
- telnyx_mcp_server/server.py +497 -0
- telnyx_mcp_server/telnyx/__init__.py +1 -0
- telnyx_mcp_server/telnyx/client.py +363 -0
- telnyx_mcp_server/telnyx/services/__init__.py +0 -0
- telnyx_mcp_server/telnyx/services/assistants.py +155 -0
- telnyx_mcp_server/telnyx/services/call_control.py +217 -0
- telnyx_mcp_server/telnyx/services/cloud_storage.py +289 -0
- telnyx_mcp_server/telnyx/services/connections.py +92 -0
- telnyx_mcp_server/telnyx/services/embeddings.py +52 -0
- telnyx_mcp_server/telnyx/services/messaging.py +93 -0
- telnyx_mcp_server/telnyx/services/messaging_profiles.py +196 -0
- telnyx_mcp_server/telnyx/services/numbers.py +193 -0
- telnyx_mcp_server/telnyx/services/secrets.py +74 -0
- telnyx_mcp_server/tools/__init__.py +126 -0
- telnyx_mcp_server/tools/assistants.py +313 -0
- telnyx_mcp_server/tools/call_control.py +242 -0
- telnyx_mcp_server/tools/cloud_storage.py +183 -0
- telnyx_mcp_server/tools/connections.py +78 -0
- telnyx_mcp_server/tools/embeddings.py +80 -0
- telnyx_mcp_server/tools/messaging.py +57 -0
- telnyx_mcp_server/tools/messaging_profiles.py +123 -0
- telnyx_mcp_server/tools/phone_numbers.py +161 -0
- telnyx_mcp_server/tools/secrets.py +75 -0
- telnyx_mcp_server/tools/sms_conversations.py +455 -0
- telnyx_mcp_server/tools/webhooks.py +111 -0
- telnyx_mcp_server/utils/__init__.py +0 -0
- telnyx_mcp_server/utils/error_handler.py +30 -0
- telnyx_mcp_server/utils/logger.py +32 -0
- telnyx_mcp_server/utils/service.py +33 -0
- telnyx_mcp_server/webhook/__init__.py +25 -0
- telnyx_mcp_server/webhook/handler.py +596 -0
- telnyx_mcp_server/webhook/server.py +369 -0
- telnyx_mcp_server_fastmcp-0.1.3.dist-info/METADATA +430 -0
- telnyx_mcp_server_fastmcp-0.1.3.dist-info/RECORD +40 -0
- telnyx_mcp_server_fastmcp-0.1.3.dist-info/WHEEL +4 -0
- telnyx_mcp_server_fastmcp-0.1.3.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""Telnyx call control service."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from ...utils.logger import get_logger
|
|
6
|
+
from ..client import TelnyxClient
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CallControlService:
|
|
12
|
+
"""Service for managing Telnyx calls."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, client: Optional[TelnyxClient] = None):
|
|
15
|
+
"""Initialize the service with a Telnyx client."""
|
|
16
|
+
self.client = client or TelnyxClient()
|
|
17
|
+
|
|
18
|
+
def list_call_control_applications(
|
|
19
|
+
self,
|
|
20
|
+
request: Dict[str, Any],
|
|
21
|
+
) -> Dict[str, Any]:
|
|
22
|
+
"""List call control applications.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
request: Request parameters for listing call control applications
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dict[str, Any]: Response data
|
|
29
|
+
"""
|
|
30
|
+
params = {
|
|
31
|
+
"page[number]": request.get("page", 1),
|
|
32
|
+
"page[size]": request.get("page_size", 20),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if request.get("filter_application_name_contains"):
|
|
36
|
+
params["filter[application_name][contains]"] = request[
|
|
37
|
+
"filter_application_name_contains"
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
if request.get("filter_outbound_voice_profile_id"):
|
|
41
|
+
params["filter[outbound.outbound_voice_profile_id]"] = request[
|
|
42
|
+
"filter_outbound_voice_profile_id"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
if request.get("sort"):
|
|
46
|
+
params["sort"] = request["sort"]
|
|
47
|
+
|
|
48
|
+
response = self.client.get("call_control_applications", params=params)
|
|
49
|
+
if isinstance(response, dict):
|
|
50
|
+
return response
|
|
51
|
+
return response.json()
|
|
52
|
+
|
|
53
|
+
def get_call_control_application(
|
|
54
|
+
self,
|
|
55
|
+
request: Dict[str, Any],
|
|
56
|
+
) -> Dict[str, Any]:
|
|
57
|
+
"""Retrieve a specific call control application.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
request: Request parameters containing the call control application ID
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Dict[str, Any]: Response data
|
|
64
|
+
"""
|
|
65
|
+
application_id = request.get("id")
|
|
66
|
+
response = self.client.get(
|
|
67
|
+
f"call_control_applications/{application_id}"
|
|
68
|
+
)
|
|
69
|
+
if isinstance(response, dict):
|
|
70
|
+
return response
|
|
71
|
+
return response.json()
|
|
72
|
+
|
|
73
|
+
def create_call_control_application(
|
|
74
|
+
self,
|
|
75
|
+
request: Dict[str, Any],
|
|
76
|
+
) -> Dict[str, Any]:
|
|
77
|
+
"""Create a call control application.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
request: Request parameters for creating a call control application
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Dict[str, Any]: Response data
|
|
84
|
+
"""
|
|
85
|
+
# Create a copy of the request to avoid modifying the original
|
|
86
|
+
data = request.copy()
|
|
87
|
+
|
|
88
|
+
response = self.client.post("call_control_applications", data=data)
|
|
89
|
+
if isinstance(response, dict):
|
|
90
|
+
return response
|
|
91
|
+
return response.json()
|
|
92
|
+
|
|
93
|
+
def make_call(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
94
|
+
"""Make a call.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
data: Call request parameters
|
|
98
|
+
Note: connection_id and call_control_application_id are the same thing,
|
|
99
|
+
either can be used to specify the application for the call.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Dict[str, Any]: Response data
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
# Rename from_ to from as required by the API
|
|
106
|
+
if "from_" in data:
|
|
107
|
+
data["from"] = data.pop("from_")
|
|
108
|
+
|
|
109
|
+
response = self.client.post("/calls", data=data)
|
|
110
|
+
return response
|
|
111
|
+
|
|
112
|
+
def hangup(
|
|
113
|
+
self, call_control_id: str, data: Dict[str, Any]
|
|
114
|
+
) -> Dict[str, Any]:
|
|
115
|
+
"""Hang up a call.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
call_control_id: Call control ID
|
|
119
|
+
data: Hangup request parameters
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Dict[str, Any]: Response data
|
|
123
|
+
"""
|
|
124
|
+
response = self.client.post(
|
|
125
|
+
f"/calls/{call_control_id}/actions/hangup", data=data
|
|
126
|
+
)
|
|
127
|
+
return response
|
|
128
|
+
|
|
129
|
+
def playback_start(
|
|
130
|
+
self, call_control_id: str, data: Dict[str, Any]
|
|
131
|
+
) -> Dict[str, Any]:
|
|
132
|
+
"""Start audio playback on a call.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
call_control_id: Call control ID
|
|
136
|
+
data: Playback request parameters
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Dict[str, Any]: Response data
|
|
140
|
+
"""
|
|
141
|
+
response = self.client.post(
|
|
142
|
+
f"/calls/{call_control_id}/actions/playback_start", data=data
|
|
143
|
+
)
|
|
144
|
+
return response
|
|
145
|
+
|
|
146
|
+
def playback_stop(
|
|
147
|
+
self, call_control_id: str, data: Dict[str, Any]
|
|
148
|
+
) -> Dict[str, Any]:
|
|
149
|
+
"""Stop audio playback on a call.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
call_control_id: Call control ID
|
|
153
|
+
data: Playback stop request parameters
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Dict[str, Any]: Response data
|
|
157
|
+
"""
|
|
158
|
+
response = self.client.post(
|
|
159
|
+
f"/calls/{call_control_id}/actions/playback_stop", data=data
|
|
160
|
+
)
|
|
161
|
+
return response
|
|
162
|
+
|
|
163
|
+
def send_dtmf(
|
|
164
|
+
self, call_control_id: str, data: Dict[str, Any]
|
|
165
|
+
) -> Dict[str, Any]:
|
|
166
|
+
"""Send DTMF tones on a call.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
call_control_id: Call control ID
|
|
170
|
+
data: DTMF request parameters
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Dict[str, Any]: Response data
|
|
174
|
+
"""
|
|
175
|
+
response = self.client.post(
|
|
176
|
+
f"/calls/{call_control_id}/actions/send_dtmf", data=data
|
|
177
|
+
)
|
|
178
|
+
return response
|
|
179
|
+
|
|
180
|
+
def speak(
|
|
181
|
+
self, call_control_id: str, data: Dict[str, Any]
|
|
182
|
+
) -> Dict[str, Any]:
|
|
183
|
+
"""Speak text on a call.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
call_control_id: Call control ID
|
|
187
|
+
data: Speak request parameters
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Dict[str, Any]: Response data
|
|
191
|
+
"""
|
|
192
|
+
response = self.client.post(
|
|
193
|
+
f"/calls/{call_control_id}/actions/speak", data=data
|
|
194
|
+
)
|
|
195
|
+
return response
|
|
196
|
+
|
|
197
|
+
def transfer(
|
|
198
|
+
self, call_control_id: str, data: Dict[str, Any]
|
|
199
|
+
) -> Dict[str, Any]:
|
|
200
|
+
"""Transfer a call.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
call_control_id: Call control ID
|
|
204
|
+
data: Transfer request parameters
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Dict[str, Any]: Response data
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
# Rename from_ to from as required by the API
|
|
211
|
+
if "from_" in data:
|
|
212
|
+
data["from"] = data.pop("from_")
|
|
213
|
+
|
|
214
|
+
response = self.client.post(
|
|
215
|
+
f"/calls/{call_control_id}/actions/transfer", data=data
|
|
216
|
+
)
|
|
217
|
+
return response
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
from functools import lru_cache
|
|
2
|
+
import os
|
|
3
|
+
from typing import Dict, List, Optional, TypedDict
|
|
4
|
+
|
|
5
|
+
import boto3
|
|
6
|
+
from botocore.client import Config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BucketInfo(TypedDict):
|
|
10
|
+
"""Type definition for bucket information"""
|
|
11
|
+
|
|
12
|
+
name: str
|
|
13
|
+
region: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CloudStorageService:
|
|
17
|
+
"""Service for interacting with Telnyx Cloud Storage (S3-compatible)"""
|
|
18
|
+
|
|
19
|
+
VALID_REGIONS = ["us-west-1", "us-central-1", "us-east-1"]
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
access_key_id: str,
|
|
24
|
+
secret_access_key: str,
|
|
25
|
+
default_region: str = "us-central-1",
|
|
26
|
+
bucket_name: Optional[str] = None,
|
|
27
|
+
):
|
|
28
|
+
"""Initialize the cloud storage service.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
access_key_id: AWS access key ID
|
|
32
|
+
secret_access_key: AWS secret access key
|
|
33
|
+
default_region: Default region to use when bucket location is unknown
|
|
34
|
+
bucket_name: Default bucket name to use for operations
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
ValueError: If an invalid region is provided
|
|
38
|
+
"""
|
|
39
|
+
if default_region not in self.VALID_REGIONS:
|
|
40
|
+
raise ValueError(
|
|
41
|
+
f"Invalid region. Must be one of: {', '.join(self.VALID_REGIONS)}"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Create S3 clients for each region
|
|
45
|
+
self.s3_clients: Dict[str, boto3.client] = {}
|
|
46
|
+
for region in self.VALID_REGIONS:
|
|
47
|
+
endpoint_url = f"https://{region}.telnyxcloudstorage.com"
|
|
48
|
+
self.s3_clients[region] = boto3.client(
|
|
49
|
+
"s3",
|
|
50
|
+
aws_access_key_id=access_key_id,
|
|
51
|
+
aws_secret_access_key=secret_access_key,
|
|
52
|
+
endpoint_url=endpoint_url,
|
|
53
|
+
region_name=region,
|
|
54
|
+
config=Config(signature_version="s3v4"),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
self.default_region = default_region
|
|
58
|
+
self.default_bucket_name = bucket_name
|
|
59
|
+
self._bucket_region_cache: Dict[str, str] = {}
|
|
60
|
+
|
|
61
|
+
def list_buckets(self) -> List[BucketInfo]:
|
|
62
|
+
"""List all buckets across all regions.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
List[BucketInfo]: List of dictionaries containing bucket information:
|
|
66
|
+
- name: Name of the bucket
|
|
67
|
+
- region: Region where the bucket is located
|
|
68
|
+
|
|
69
|
+
Note:
|
|
70
|
+
This method may take some time as it needs to:
|
|
71
|
+
1. List buckets from each region
|
|
72
|
+
2. Get the location of each bucket
|
|
73
|
+
3. Deduplicate the results
|
|
74
|
+
"""
|
|
75
|
+
seen_buckets = set()
|
|
76
|
+
buckets: List[BucketInfo] = []
|
|
77
|
+
|
|
78
|
+
# Try listing buckets from each region
|
|
79
|
+
for region in self.VALID_REGIONS:
|
|
80
|
+
try:
|
|
81
|
+
response = self.s3_clients[region].list_buckets()
|
|
82
|
+
for bucket in response.get("Buckets", []):
|
|
83
|
+
bucket_name = bucket["Name"]
|
|
84
|
+
|
|
85
|
+
# Skip if we've already processed this bucket
|
|
86
|
+
if bucket_name in seen_buckets:
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
# Get the actual region for this bucket
|
|
91
|
+
bucket_region = self._get_bucket_region(bucket_name)
|
|
92
|
+
buckets.append(
|
|
93
|
+
{"name": bucket_name, "region": bucket_region}
|
|
94
|
+
)
|
|
95
|
+
seen_buckets.add(bucket_name)
|
|
96
|
+
except ValueError:
|
|
97
|
+
# Skip buckets whose region we can't determine
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
except Exception:
|
|
101
|
+
# If listing fails in this region, continue to the next
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
return buckets
|
|
105
|
+
|
|
106
|
+
def _get_bucket_name(self, bucket_name: Optional[str] = None) -> str:
|
|
107
|
+
"""Get the bucket name to use for an operation.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
bucket_name: Name of the bucket. If None, uses default bucket.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
str: The bucket name to use
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
ValueError: If no bucket name is provided or set as default
|
|
117
|
+
"""
|
|
118
|
+
bucket_name = bucket_name or self.default_bucket_name
|
|
119
|
+
if not bucket_name:
|
|
120
|
+
raise ValueError(
|
|
121
|
+
"Bucket name must be provided either during initialization or method call"
|
|
122
|
+
)
|
|
123
|
+
return bucket_name
|
|
124
|
+
|
|
125
|
+
@lru_cache(maxsize=100)
|
|
126
|
+
def _get_bucket_region(self, bucket_name: str) -> str:
|
|
127
|
+
"""Get the region where a bucket is located (with caching).
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
bucket_name: Name of the bucket
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
str: The region where the bucket is located
|
|
134
|
+
|
|
135
|
+
Raises:
|
|
136
|
+
ValueError: If the bucket's region cannot be determined
|
|
137
|
+
"""
|
|
138
|
+
# Try to get location from default region first
|
|
139
|
+
try:
|
|
140
|
+
response = self.s3_clients[
|
|
141
|
+
self.default_region
|
|
142
|
+
].get_bucket_location(Bucket=bucket_name)
|
|
143
|
+
location = response.get("LocationConstraint") or "us-east-1"
|
|
144
|
+
if location in self.VALID_REGIONS:
|
|
145
|
+
return location
|
|
146
|
+
except Exception:
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
# If that fails, try each region until we find it
|
|
150
|
+
for region in self.VALID_REGIONS:
|
|
151
|
+
if region == self.default_region:
|
|
152
|
+
continue
|
|
153
|
+
try:
|
|
154
|
+
response = self.s3_clients[region].get_bucket_location(
|
|
155
|
+
Bucket=bucket_name
|
|
156
|
+
)
|
|
157
|
+
location = response.get("LocationConstraint") or "us-east-1"
|
|
158
|
+
if location in self.VALID_REGIONS:
|
|
159
|
+
return location
|
|
160
|
+
except Exception:
|
|
161
|
+
continue
|
|
162
|
+
|
|
163
|
+
raise ValueError(
|
|
164
|
+
f"Could not determine region for bucket: {bucket_name}"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def _get_client_for_bucket(self, bucket_name: str) -> boto3.client:
|
|
168
|
+
"""Get the appropriate S3 client for the given bucket.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
bucket_name: Name of the bucket
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
boto3.client: The S3 client for the bucket's region
|
|
175
|
+
"""
|
|
176
|
+
region = self._get_bucket_region(bucket_name)
|
|
177
|
+
return self.s3_clients[region]
|
|
178
|
+
|
|
179
|
+
def upload_file(
|
|
180
|
+
self,
|
|
181
|
+
file_path: str,
|
|
182
|
+
object_name: Optional[str] = None,
|
|
183
|
+
bucket_name: Optional[str] = None,
|
|
184
|
+
):
|
|
185
|
+
"""Upload a file to cloud storage.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
file_path: **ABSOLUTE PATH** to the file to upload
|
|
189
|
+
object_name: Name to give the object in storage (defaults to file name)
|
|
190
|
+
bucket_name: Bucket to upload to (defaults to instance default)
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
str: `Success!!` if it uploaded, otherwise returns an exception message
|
|
194
|
+
"""
|
|
195
|
+
if not object_name:
|
|
196
|
+
object_name = os.path.basename(file_path)
|
|
197
|
+
|
|
198
|
+
bucket = self._get_bucket_name(bucket_name)
|
|
199
|
+
s3 = self._get_client_for_bucket(bucket)
|
|
200
|
+
try:
|
|
201
|
+
s3.upload_file(file_path, bucket, object_name)
|
|
202
|
+
return "Success!!"
|
|
203
|
+
except Exception as e:
|
|
204
|
+
return f"An error occurred: {e}"
|
|
205
|
+
|
|
206
|
+
def create_bucket(self, bucket_name: str, region: str) -> str:
|
|
207
|
+
"""Create a new bucket.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
bucket_name: Name of the bucket to create
|
|
211
|
+
region: Region to create the bucket in
|
|
212
|
+
Returns:
|
|
213
|
+
str: `Success!!` if it uploaded, otherwise returns an exception message
|
|
214
|
+
"""
|
|
215
|
+
region = region or self.default_region
|
|
216
|
+
s3 = self.s3_clients[region]
|
|
217
|
+
try:
|
|
218
|
+
s3.create_bucket(
|
|
219
|
+
Bucket=bucket_name,
|
|
220
|
+
CreateBucketConfiguration={"LocationConstraint": region},
|
|
221
|
+
)
|
|
222
|
+
return "Success!!"
|
|
223
|
+
except Exception as e:
|
|
224
|
+
return f"An error occurred: {e}"
|
|
225
|
+
|
|
226
|
+
def download_file(
|
|
227
|
+
self,
|
|
228
|
+
object_name: str,
|
|
229
|
+
file_path: str,
|
|
230
|
+
bucket_name: Optional[str] = None,
|
|
231
|
+
) -> None:
|
|
232
|
+
"""Download a file from cloud storage.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
object_name: Name of the object to download
|
|
236
|
+
file_path: Path where to save the downloaded file
|
|
237
|
+
bucket_name: Bucket to download from (defaults to instance default)
|
|
238
|
+
"""
|
|
239
|
+
bucket = self._get_bucket_name(bucket_name)
|
|
240
|
+
s3 = self._get_client_for_bucket(bucket)
|
|
241
|
+
s3.download_file(bucket, object_name, file_path)
|
|
242
|
+
|
|
243
|
+
def list_objects(
|
|
244
|
+
self, prefix: str = "", bucket_name: Optional[str] = None
|
|
245
|
+
) -> List[str]:
|
|
246
|
+
"""List objects in a bucket with optional prefix filtering.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
prefix: Only list objects beginning with this prefix
|
|
250
|
+
bucket_name: Bucket to list from (defaults to instance default)
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
List[str]: List of object names
|
|
254
|
+
"""
|
|
255
|
+
bucket = self._get_bucket_name(bucket_name)
|
|
256
|
+
s3 = self._get_client_for_bucket(bucket)
|
|
257
|
+
paginator = s3.get_paginator("list_objects_v2")
|
|
258
|
+
|
|
259
|
+
object_names = []
|
|
260
|
+
for page in paginator.paginate(Bucket=bucket, Prefix=prefix):
|
|
261
|
+
if "Contents" in page:
|
|
262
|
+
object_names.extend(obj["Key"] for obj in page["Contents"])
|
|
263
|
+
|
|
264
|
+
return object_names
|
|
265
|
+
|
|
266
|
+
def delete_object(
|
|
267
|
+
self, object_name: str, bucket_name: Optional[str] = None
|
|
268
|
+
) -> None:
|
|
269
|
+
"""Delete an object from cloud storage.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
object_name: Name of the object to delete
|
|
273
|
+
bucket_name: Bucket to delete from (defaults to instance default)
|
|
274
|
+
"""
|
|
275
|
+
bucket = self._get_bucket_name(bucket_name)
|
|
276
|
+
s3 = self._get_client_for_bucket(bucket)
|
|
277
|
+
s3.delete_object(Bucket=bucket, Key=object_name)
|
|
278
|
+
|
|
279
|
+
def get_bucket_location(self, bucket_name: Optional[str] = None) -> str:
|
|
280
|
+
"""Get the region where a bucket is located.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
bucket_name: Name of the bucket. If None, uses default bucket.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
str: The region where the bucket is located
|
|
287
|
+
"""
|
|
288
|
+
bucket = self._get_bucket_name(bucket_name)
|
|
289
|
+
return self._get_bucket_region(bucket)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Telnyx connections service."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from ...utils.logger import get_logger
|
|
6
|
+
from ..client import TelnyxClient
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ConnectionsService:
|
|
12
|
+
"""Service for managing Telnyx connections."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, client: Optional[TelnyxClient] = None):
|
|
15
|
+
"""Initialize the service with a Telnyx client."""
|
|
16
|
+
self.client = client or TelnyxClient()
|
|
17
|
+
|
|
18
|
+
def list_connections(
|
|
19
|
+
self,
|
|
20
|
+
request: Dict[str, Any],
|
|
21
|
+
) -> Dict[str, Any]:
|
|
22
|
+
"""List connections.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
request: Request parameters for listing connections
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dict[str, Any]: Response data
|
|
29
|
+
"""
|
|
30
|
+
params = {
|
|
31
|
+
"page[number]": request.get("page", 1),
|
|
32
|
+
"page[size]": request.get("page_size", 20),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if request.get("filter_connection_name_contains"):
|
|
36
|
+
params["filter[connection_name_contains]"] = request[
|
|
37
|
+
"filter_connection_name_contains"
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
if request.get("filter_outbound_voice_profile_id"):
|
|
41
|
+
params["filter[outbound_voice_profile_id]"] = request[
|
|
42
|
+
"filter_outbound_voice_profile_id"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
if request.get("sort"):
|
|
46
|
+
params["sort"] = request["sort"]
|
|
47
|
+
|
|
48
|
+
response = self.client.get("connections", params=params)
|
|
49
|
+
if isinstance(response, dict):
|
|
50
|
+
return response
|
|
51
|
+
return response.json()
|
|
52
|
+
|
|
53
|
+
def get_connection(self, connection_id: str) -> Dict[str, Any]:
|
|
54
|
+
"""Get a connection by ID.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
connection_id: Connection ID
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Dict[str, Any]: Response data
|
|
61
|
+
"""
|
|
62
|
+
response = self.client.get(f"connections/{connection_id}")
|
|
63
|
+
if isinstance(response, dict):
|
|
64
|
+
return response
|
|
65
|
+
return response.json()
|
|
66
|
+
|
|
67
|
+
def update_connection(
|
|
68
|
+
self,
|
|
69
|
+
connection_id: str,
|
|
70
|
+
data: Dict[str, Any],
|
|
71
|
+
) -> Dict[str, Any]:
|
|
72
|
+
"""Update a connection.
|
|
73
|
+
|
|
74
|
+
Note:
|
|
75
|
+
The Telnyx API does not support updating connections directly.
|
|
76
|
+
Only GET, HEAD, and OPTIONS methods are allowed.
|
|
77
|
+
Please create a new connection with the desired settings instead.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
connection_id: Connection ID
|
|
81
|
+
data: Update data
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Dict[str, Any]: Response data
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
Exception: The Telnyx API does not support updating connections directly.
|
|
88
|
+
"""
|
|
89
|
+
raise Exception(
|
|
90
|
+
"The Telnyx API does not support updating connections directly. "
|
|
91
|
+
"Please create a new connection with the desired settings instead."
|
|
92
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Telnyx embeddings service."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from ...utils.logger import get_logger
|
|
6
|
+
from ..client import TelnyxClient
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EmbeddingsService:
|
|
12
|
+
"""Telnyx embeddings service."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, client: Optional[TelnyxClient] = None):
|
|
15
|
+
"""Initialize the service.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
client: Telnyx API client (creates a new one if not provided)
|
|
19
|
+
"""
|
|
20
|
+
self.client = client or TelnyxClient()
|
|
21
|
+
|
|
22
|
+
def list_embedded_buckets(
|
|
23
|
+
self,
|
|
24
|
+
) -> Dict[str, Any]:
|
|
25
|
+
"""List embedded buckets.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dict[str, Any]: Response data
|
|
29
|
+
"""
|
|
30
|
+
return self.client.get("ai/embeddings/buckets")
|
|
31
|
+
|
|
32
|
+
def embed_url(
|
|
33
|
+
self,
|
|
34
|
+
request: Dict[str, Any],
|
|
35
|
+
) -> Dict[str, Any]:
|
|
36
|
+
"""Embed a URL.
|
|
37
|
+
Args:
|
|
38
|
+
request: request containing the url to embed `{url: str}`
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Dict[str, Any]: Response data
|
|
43
|
+
"""
|
|
44
|
+
return self.client.post("ai/embeddings/url", data=request)
|
|
45
|
+
|
|
46
|
+
def create_embeddings(self, request: Dict[str, Any]) -> Dict[str, Any]:
|
|
47
|
+
"""Create embeddings for a list of texts.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Dict[str, Any]: Response data
|
|
51
|
+
"""
|
|
52
|
+
return self.client.post("ai/embeddings", data=request)
|