universal-mcp-applications 0.1.33__py3-none-any.whl → 0.1.39rc16__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 universal-mcp-applications might be problematic. Click here for more details.
- universal_mcp/applications/BEST_PRACTICES.md +1 -1
- universal_mcp/applications/ahrefs/app.py +92 -238
- universal_mcp/applications/airtable/app.py +36 -135
- universal_mcp/applications/apollo/app.py +124 -477
- universal_mcp/applications/asana/app.py +605 -1755
- universal_mcp/applications/aws_s3/app.py +63 -119
- universal_mcp/applications/bill/app.py +644 -2055
- universal_mcp/applications/box/app.py +1246 -4159
- universal_mcp/applications/braze/app.py +410 -1476
- universal_mcp/applications/browser_use/README.md +15 -1
- universal_mcp/applications/browser_use/__init__.py +1 -0
- universal_mcp/applications/browser_use/app.py +91 -26
- universal_mcp/applications/cal_com_v2/app.py +207 -625
- universal_mcp/applications/calendly/app.py +103 -242
- universal_mcp/applications/canva/app.py +75 -140
- universal_mcp/applications/clickup/app.py +331 -798
- universal_mcp/applications/coda/app.py +240 -520
- universal_mcp/applications/confluence/app.py +497 -1285
- universal_mcp/applications/contentful/app.py +40 -155
- universal_mcp/applications/crustdata/app.py +44 -123
- universal_mcp/applications/dialpad/app.py +451 -924
- universal_mcp/applications/digitalocean/app.py +2071 -6082
- universal_mcp/applications/domain_checker/app.py +3 -54
- universal_mcp/applications/e2b/app.py +17 -68
- universal_mcp/applications/elevenlabs/README.md +27 -3
- universal_mcp/applications/elevenlabs/app.py +741 -74
- universal_mcp/applications/exa/README.md +8 -4
- universal_mcp/applications/exa/app.py +415 -186
- universal_mcp/applications/falai/README.md +5 -7
- universal_mcp/applications/falai/app.py +156 -232
- universal_mcp/applications/figma/app.py +91 -175
- universal_mcp/applications/file_system/app.py +2 -13
- universal_mcp/applications/firecrawl/app.py +198 -176
- universal_mcp/applications/fireflies/app.py +59 -281
- universal_mcp/applications/fpl/app.py +92 -529
- universal_mcp/applications/fpl/utils/fixtures.py +15 -49
- universal_mcp/applications/fpl/utils/helper.py +25 -89
- universal_mcp/applications/fpl/utils/league_utils.py +20 -64
- universal_mcp/applications/ghost_content/app.py +70 -179
- universal_mcp/applications/github/app.py +30 -67
- universal_mcp/applications/gong/app.py +142 -302
- universal_mcp/applications/google_calendar/app.py +26 -78
- universal_mcp/applications/google_docs/README.md +15 -14
- universal_mcp/applications/google_docs/app.py +103 -206
- universal_mcp/applications/google_drive/app.py +194 -793
- universal_mcp/applications/google_gemini/app.py +68 -59
- universal_mcp/applications/google_mail/README.md +1 -0
- universal_mcp/applications/google_mail/app.py +93 -214
- universal_mcp/applications/google_searchconsole/app.py +25 -58
- universal_mcp/applications/google_sheet/README.md +2 -1
- universal_mcp/applications/google_sheet/app.py +226 -624
- universal_mcp/applications/google_sheet/helper.py +26 -53
- universal_mcp/applications/hashnode/app.py +57 -269
- universal_mcp/applications/heygen/README.md +10 -32
- universal_mcp/applications/heygen/app.py +339 -811
- universal_mcp/applications/http_tools/app.py +10 -32
- universal_mcp/applications/hubspot/README.md +1 -1
- universal_mcp/applications/hubspot/app.py +7508 -99
- universal_mcp/applications/jira/app.py +2419 -8334
- universal_mcp/applications/klaviyo/app.py +739 -1621
- universal_mcp/applications/linkedin/README.md +18 -1
- universal_mcp/applications/linkedin/app.py +729 -251
- universal_mcp/applications/mailchimp/app.py +696 -1851
- universal_mcp/applications/markitdown/app.py +8 -20
- universal_mcp/applications/miro/app.py +333 -815
- universal_mcp/applications/ms_teams/app.py +420 -1407
- universal_mcp/applications/neon/app.py +144 -250
- universal_mcp/applications/notion/app.py +38 -53
- universal_mcp/applications/onedrive/app.py +26 -48
- universal_mcp/applications/openai/app.py +43 -166
- universal_mcp/applications/outlook/README.md +22 -9
- universal_mcp/applications/outlook/app.py +403 -141
- universal_mcp/applications/perplexity/README.md +2 -1
- universal_mcp/applications/perplexity/app.py +161 -20
- universal_mcp/applications/pipedrive/app.py +1021 -3331
- universal_mcp/applications/posthog/app.py +272 -541
- universal_mcp/applications/reddit/app.py +65 -164
- universal_mcp/applications/resend/app.py +72 -139
- universal_mcp/applications/retell/app.py +23 -50
- universal_mcp/applications/rocketlane/app.py +252 -965
- universal_mcp/applications/scraper/app.py +114 -142
- universal_mcp/applications/semanticscholar/app.py +36 -78
- universal_mcp/applications/semrush/app.py +44 -78
- universal_mcp/applications/sendgrid/app.py +826 -1576
- universal_mcp/applications/sentry/app.py +444 -1079
- universal_mcp/applications/serpapi/app.py +44 -146
- universal_mcp/applications/sharepoint/app.py +27 -49
- universal_mcp/applications/shopify/app.py +1748 -4486
- universal_mcp/applications/shortcut/app.py +275 -536
- universal_mcp/applications/slack/app.py +43 -125
- universal_mcp/applications/spotify/app.py +206 -405
- universal_mcp/applications/supabase/app.py +174 -283
- universal_mcp/applications/tavily/app.py +2 -2
- universal_mcp/applications/trello/app.py +853 -2816
- universal_mcp/applications/twilio/app.py +27 -62
- universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
- universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
- universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
- universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
- universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
- universal_mcp/applications/whatsapp/app.py +35 -186
- universal_mcp/applications/whatsapp/audio.py +2 -6
- universal_mcp/applications/whatsapp/whatsapp.py +17 -51
- universal_mcp/applications/whatsapp_business/app.py +86 -299
- universal_mcp/applications/wrike/app.py +80 -153
- universal_mcp/applications/yahoo_finance/app.py +19 -65
- universal_mcp/applications/youtube/app.py +120 -306
- universal_mcp/applications/zenquotes/app.py +3 -3
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/METADATA +4 -2
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/RECORD +115 -119
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/WHEEL +1 -1
- universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
- universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
- universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
- universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,42 +1,18 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import sys
|
|
3
3
|
from typing import Any
|
|
4
|
-
|
|
5
4
|
import dns.resolver
|
|
6
5
|
import requests
|
|
7
6
|
from universal_mcp.applications.application import APIApplication
|
|
8
7
|
from universal_mcp.integrations import Integration
|
|
9
8
|
|
|
10
|
-
# Configure logging
|
|
11
9
|
logging.basicConfig(
|
|
12
|
-
level=logging.INFO,
|
|
13
|
-
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
14
|
-
handlers=[logging.StreamHandler(sys.stderr)],
|
|
10
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[logging.StreamHandler(sys.stderr)]
|
|
15
11
|
)
|
|
16
|
-
|
|
17
12
|
logger = logging.getLogger("domain_checker")
|
|
18
|
-
|
|
19
|
-
# Constants
|
|
20
13
|
RDAP_BOOTSTRAP_URL = "https://data.iana.org/rdap/dns.json"
|
|
21
14
|
USER_AGENT = "DomainCheckerBot/1.0"
|
|
22
|
-
|
|
23
|
-
# Top TLDs to check
|
|
24
|
-
TOP_TLDS = [
|
|
25
|
-
"com",
|
|
26
|
-
"net",
|
|
27
|
-
"org",
|
|
28
|
-
"io",
|
|
29
|
-
"co",
|
|
30
|
-
"app",
|
|
31
|
-
"dev",
|
|
32
|
-
"ai",
|
|
33
|
-
"me",
|
|
34
|
-
"info",
|
|
35
|
-
"xyz",
|
|
36
|
-
"online",
|
|
37
|
-
"site",
|
|
38
|
-
"tech",
|
|
39
|
-
]
|
|
15
|
+
TOP_TLDS = ["com", "net", "org", "io", "co", "app", "dev", "ai", "me", "info", "xyz", "online", "site", "tech"]
|
|
40
16
|
|
|
41
17
|
|
|
42
18
|
class DomainCheckerApp(APIApplication):
|
|
@@ -52,22 +28,16 @@ class DomainCheckerApp(APIApplication):
|
|
|
52
28
|
Fetches a domain's registration details from Registration Data Access Protocol (RDAP) servers. It dynamically selects the appropriate server URL based on the domain's TLD, with special handling for common ones. Returns the JSON data as a dictionary or None if the request fails or data is unavailable.
|
|
53
29
|
"""
|
|
54
30
|
try:
|
|
55
|
-
# Special case for .ch and .li domains
|
|
56
31
|
tld = domain.split(".")[-1].lower()
|
|
57
32
|
if tld in ["ch", "li"]:
|
|
58
33
|
rdap_url = f"https://rdap.nic.{tld}/domain/{domain}"
|
|
59
|
-
# Use common RDAP servers for known TLDs
|
|
60
34
|
elif tld in ["com", "net"]:
|
|
61
35
|
rdap_url = f"https://rdap.verisign.com/{tld}/v1/domain/{domain}"
|
|
62
36
|
elif tld == "org":
|
|
63
|
-
rdap_url =
|
|
64
|
-
f"https://rdap.publicinterestregistry.org/rdap/domain/{domain}"
|
|
65
|
-
)
|
|
37
|
+
rdap_url = f"https://rdap.publicinterestregistry.org/rdap/domain/{domain}"
|
|
66
38
|
else:
|
|
67
39
|
rdap_url = f"https://rdap.org/domain/{domain}"
|
|
68
|
-
|
|
69
40
|
headers = {"Accept": "application/rdap+json", "User-Agent": USER_AGENT}
|
|
70
|
-
|
|
71
41
|
response = requests.get(rdap_url, headers=headers, timeout=5)
|
|
72
42
|
if response.status_code == 200:
|
|
73
43
|
return response.json()
|
|
@@ -122,21 +92,13 @@ class DomainCheckerApp(APIApplication):
|
|
|
122
92
|
domain, availability, registration, dns, rdap, important
|
|
123
93
|
"""
|
|
124
94
|
logger.info(f"Checking domain: {domain}")
|
|
125
|
-
|
|
126
|
-
# First check DNS
|
|
127
95
|
has_dns = await self._check_dns(domain)
|
|
128
|
-
|
|
129
96
|
if has_dns:
|
|
130
|
-
# Domain exists, get RDAP data if possible
|
|
131
97
|
rdap_data = await self._get_rdap_data(domain)
|
|
132
|
-
|
|
133
98
|
if rdap_data:
|
|
134
|
-
# Extract data from RDAP
|
|
135
99
|
registrar = "Unknown"
|
|
136
100
|
reg_date = "Unknown"
|
|
137
101
|
exp_date = "Unknown"
|
|
138
|
-
|
|
139
|
-
# Extract registrar
|
|
140
102
|
entities = rdap_data.get("entities", [])
|
|
141
103
|
for entity in entities:
|
|
142
104
|
if "registrar" in entity.get("roles", []):
|
|
@@ -146,15 +108,12 @@ class DomainCheckerApp(APIApplication):
|
|
|
146
108
|
if entry[0] in ["fn", "org"] and len(entry) > 3:
|
|
147
109
|
registrar = entry[3]
|
|
148
110
|
break
|
|
149
|
-
|
|
150
|
-
# Extract dates
|
|
151
111
|
events = rdap_data.get("events", [])
|
|
152
112
|
for event in events:
|
|
153
113
|
if event.get("eventAction") == "registration":
|
|
154
114
|
reg_date = event.get("eventDate", "Unknown")
|
|
155
115
|
elif event.get("eventAction") == "expiration":
|
|
156
116
|
exp_date = event.get("eventDate", "Unknown")
|
|
157
|
-
|
|
158
117
|
return {
|
|
159
118
|
"domain": domain,
|
|
160
119
|
"status": "Registered",
|
|
@@ -175,8 +134,6 @@ class DomainCheckerApp(APIApplication):
|
|
|
175
134
|
"rdap_data_available": False,
|
|
176
135
|
"note": "Domain has DNS records but RDAP data couldn't be retrieved",
|
|
177
136
|
}
|
|
178
|
-
|
|
179
|
-
# Try RDAP one more time even if DNS not found
|
|
180
137
|
rdap_data = await self._get_rdap_data(domain)
|
|
181
138
|
if rdap_data:
|
|
182
139
|
return {
|
|
@@ -189,8 +146,6 @@ class DomainCheckerApp(APIApplication):
|
|
|
189
146
|
"rdap_data_available": True,
|
|
190
147
|
"note": "Domain found in RDAP registry",
|
|
191
148
|
}
|
|
192
|
-
|
|
193
|
-
# If we get here, the domain is likely available
|
|
194
149
|
return {
|
|
195
150
|
"domain": domain,
|
|
196
151
|
"status": "Available",
|
|
@@ -233,17 +188,12 @@ class DomainCheckerApp(APIApplication):
|
|
|
233
188
|
tld, keyword, domain-search, availability, bulk-check, important
|
|
234
189
|
"""
|
|
235
190
|
logger.info(f"Checking keyword: {keyword} across TLDs")
|
|
236
|
-
|
|
237
191
|
available = []
|
|
238
192
|
taken = []
|
|
239
|
-
|
|
240
|
-
# Check each TLD in sequence
|
|
241
193
|
for tld in TOP_TLDS:
|
|
242
194
|
domain = f"{keyword}.{tld}"
|
|
243
195
|
has_dns = await self._check_dns(domain)
|
|
244
|
-
|
|
245
196
|
if not has_dns:
|
|
246
|
-
# Double-check with RDAP if no DNS
|
|
247
197
|
rdap_data = await self._get_rdap_data(domain)
|
|
248
198
|
if not rdap_data:
|
|
249
199
|
available.append(domain)
|
|
@@ -251,7 +201,6 @@ class DomainCheckerApp(APIApplication):
|
|
|
251
201
|
taken.append(domain)
|
|
252
202
|
else:
|
|
253
203
|
taken.append(domain)
|
|
254
|
-
|
|
255
204
|
return {
|
|
256
205
|
"keyword": keyword,
|
|
257
206
|
"tlds_checked": len(TOP_TLDS),
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Annotated, Any
|
|
3
|
-
|
|
4
3
|
from loguru import logger
|
|
5
4
|
|
|
6
5
|
try:
|
|
7
6
|
from e2b_code_interpreter import Sandbox
|
|
8
|
-
|
|
9
7
|
except ImportError:
|
|
10
8
|
Sandbox = None
|
|
11
|
-
logger.error(
|
|
12
|
-
"Failed to import E2B Sandbox. Please ensure 'e2b_code_interpreter' is installed."
|
|
13
|
-
)
|
|
14
|
-
|
|
9
|
+
logger.error("Failed to import E2B Sandbox. Please ensure 'e2b_code_interpreter' is installed.")
|
|
15
10
|
from universal_mcp.applications.application import APIApplication
|
|
16
11
|
from universal_mcp.exceptions import NotAuthorizedError, ToolError
|
|
17
12
|
from universal_mcp.integrations import Integration
|
|
@@ -28,66 +23,40 @@ class E2bApp(APIApplication):
|
|
|
28
23
|
super().__init__(name="e2b", integration=integration, **kwargs)
|
|
29
24
|
self._e2b_api_key: str | None = None
|
|
30
25
|
if Sandbox is None:
|
|
31
|
-
logger.warning(
|
|
32
|
-
"E2B Sandbox SDK is not available. E2B tools will not function."
|
|
33
|
-
)
|
|
26
|
+
logger.warning("E2B Sandbox SDK is not available. E2B tools will not function.")
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
def e2b_api_key(self) -> str:
|
|
28
|
+
async def get_e2b_api_key(self) -> str:
|
|
37
29
|
"""
|
|
38
30
|
A property that lazily retrieves and caches the E2B API key from the configured integration. It fetches the key on the first call, handles authentication failures, and raises `NotAuthorizedError` with actionable guidance if the key cannot be obtained.
|
|
39
31
|
"""
|
|
40
32
|
if self._e2b_api_key is None:
|
|
41
33
|
if not self.integration:
|
|
42
34
|
logger.error("E2B App: Integration not configured.")
|
|
43
|
-
raise NotAuthorizedError(
|
|
44
|
-
"Integration not configured for E2B App. Cannot retrieve API key."
|
|
45
|
-
)
|
|
46
|
-
|
|
35
|
+
raise NotAuthorizedError("Integration not configured for E2B App. Cannot retrieve API key.")
|
|
47
36
|
try:
|
|
48
|
-
credentials = self.integration.
|
|
37
|
+
credentials = await self.integration.get_credentials_async()
|
|
49
38
|
except NotAuthorizedError as e:
|
|
50
|
-
logger.error(
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
raise # Re-raise the original NotAuthorizedError
|
|
39
|
+
logger.error(f"E2B App: Authorization error when fetching credentials: {e.message}")
|
|
40
|
+
raise
|
|
54
41
|
except Exception as e:
|
|
55
|
-
logger.error(
|
|
56
|
-
f"E2B App: Unexpected error when fetching credentials: {e}",
|
|
57
|
-
exc_info=True,
|
|
58
|
-
)
|
|
42
|
+
logger.error(f"E2B App: Unexpected error when fetching credentials: {e}", exc_info=True)
|
|
59
43
|
raise NotAuthorizedError(f"Failed to get E2B credentials: {e}")
|
|
60
|
-
|
|
61
|
-
api_key = (
|
|
62
|
-
credentials.get("api_key")
|
|
63
|
-
or credentials.get("API_KEY") # Check common variations
|
|
64
|
-
or credentials.get("apiKey")
|
|
65
|
-
)
|
|
66
|
-
|
|
44
|
+
api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
|
|
67
45
|
if not api_key:
|
|
68
46
|
logger.error("E2B App: API key not found in credentials.")
|
|
69
47
|
action_message = "API key for E2B is missing. Please ensure it's set in the store via MCP frontend or configuration."
|
|
70
|
-
if hasattr(self.integration, "authorize") and callable(
|
|
71
|
-
self.integration.authorize
|
|
72
|
-
):
|
|
48
|
+
if hasattr(self.integration, "authorize") and callable(self.integration.authorize):
|
|
73
49
|
try:
|
|
74
50
|
auth_details = self.integration.authorize()
|
|
75
51
|
if isinstance(auth_details, str):
|
|
76
52
|
action_message = auth_details
|
|
77
53
|
elif isinstance(auth_details, dict) and "url" in auth_details:
|
|
78
|
-
action_message =
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
elif (
|
|
82
|
-
isinstance(auth_details, dict) and "message" in auth_details
|
|
83
|
-
):
|
|
54
|
+
action_message = f"Please authorize via: {auth_details['url']}"
|
|
55
|
+
elif isinstance(auth_details, dict) and "message" in auth_details:
|
|
84
56
|
action_message = auth_details["message"]
|
|
85
57
|
except Exception as auth_e:
|
|
86
|
-
logger.warning(
|
|
87
|
-
f"Could not retrieve specific authorization action for E2B: {auth_e}"
|
|
88
|
-
)
|
|
58
|
+
logger.warning(f"Could not retrieve specific authorization action for E2B: {auth_e}")
|
|
89
59
|
raise NotAuthorizedError(action_message)
|
|
90
|
-
|
|
91
60
|
self._e2b_api_key = api_key
|
|
92
61
|
logger.info("E2B API Key successfully retrieved and cached.")
|
|
93
62
|
return self._e2b_api_key
|
|
@@ -95,40 +64,28 @@ class E2bApp(APIApplication):
|
|
|
95
64
|
def _format_execution_output(self, execution: Any) -> str:
|
|
96
65
|
"""Helper function to format the E2B execution logs nicely."""
|
|
97
66
|
output_parts = []
|
|
98
|
-
|
|
99
67
|
try:
|
|
100
68
|
logs = getattr(execution, "logs", None)
|
|
101
|
-
|
|
102
69
|
if logs is not None:
|
|
103
|
-
# Collect stdout
|
|
104
70
|
if getattr(logs, "stdout", None):
|
|
105
71
|
stdout_content = "".join(logs.stdout).strip()
|
|
106
72
|
if stdout_content:
|
|
107
73
|
output_parts.append(stdout_content)
|
|
108
|
-
|
|
109
|
-
# Collect stderr
|
|
110
74
|
if getattr(logs, "stderr", None):
|
|
111
75
|
stderr_content = "".join(logs.stderr).strip()
|
|
112
76
|
if stderr_content:
|
|
113
77
|
output_parts.append(f"--- ERROR ---\n{stderr_content}")
|
|
114
|
-
|
|
115
|
-
# Fallback: check execution.text (covers expressions returning values)
|
|
116
78
|
if not output_parts and hasattr(execution, "text"):
|
|
117
79
|
text_content = str(execution.text).strip()
|
|
118
80
|
if text_content:
|
|
119
81
|
output_parts.append(text_content)
|
|
120
|
-
|
|
121
82
|
except Exception as e:
|
|
122
83
|
output_parts.append(f"Failed to format execution output: {e}")
|
|
123
|
-
|
|
124
84
|
if not output_parts:
|
|
125
85
|
return "Execution finished with no output (stdout/stderr)."
|
|
126
|
-
|
|
127
86
|
return "\n\n".join(output_parts)
|
|
128
87
|
|
|
129
|
-
def execute_python_code(
|
|
130
|
-
self, code: Annotated[str, "The Python code to execute."]
|
|
131
|
-
) -> str:
|
|
88
|
+
async def execute_python_code(self, code: Annotated[str, "The Python code to execute."]) -> str:
|
|
132
89
|
"""
|
|
133
90
|
Executes a Python code string in a secure E2B sandbox. It authenticates using the configured API key, runs the code, and returns a formatted string containing the execution's output (stdout/stderr). It raises specific exceptions for authorization failures or general execution issues.
|
|
134
91
|
|
|
@@ -151,10 +108,9 @@ class E2bApp(APIApplication):
|
|
|
151
108
|
raise ToolError("E2B Sandbox SDK (e2b_code_interpreter) is not installed.")
|
|
152
109
|
if not code or not isinstance(code, str):
|
|
153
110
|
raise ValueError("Provided code must be a non-empty string.")
|
|
154
|
-
|
|
155
111
|
try:
|
|
156
112
|
logger.info("Attempting to execute Python code in E2B Sandbox.")
|
|
157
|
-
os.environ["E2B_API_KEY"] = self.
|
|
113
|
+
os.environ["E2B_API_KEY"] = await self.get_e2b_api_key()
|
|
158
114
|
with Sandbox.create() as sandbox:
|
|
159
115
|
logger.info("E2B Sandbox initialized. Running code.")
|
|
160
116
|
execution = sandbox.run_code(code)
|
|
@@ -164,17 +120,10 @@ class E2bApp(APIApplication):
|
|
|
164
120
|
except Exception as e:
|
|
165
121
|
logger.exception("E2B code execution failed.")
|
|
166
122
|
lower = str(e).lower()
|
|
167
|
-
if (
|
|
168
|
-
"authentication" in lower
|
|
169
|
-
or "api key" in lower
|
|
170
|
-
or "401" in lower
|
|
171
|
-
or "403" in lower
|
|
172
|
-
):
|
|
123
|
+
if "authentication" in lower or "api key" in lower or "401" in lower or ("403" in lower):
|
|
173
124
|
raise NotAuthorizedError(f"E2B authentication/permission failed: {e}")
|
|
174
125
|
raise ToolError(f"E2B code execution failed: {e}")
|
|
175
126
|
|
|
176
127
|
def list_tools(self) -> list[callable]:
|
|
177
128
|
"""Lists the tools available from the E2bApp."""
|
|
178
|
-
return [
|
|
179
|
-
self.execute_python_code,
|
|
180
|
-
]
|
|
129
|
+
return [self.execute_python_code]
|
|
@@ -9,6 +9,30 @@ This is automatically generated from OpenAPI schema for the ElevenlabsApp API.
|
|
|
9
9
|
|
|
10
10
|
| Tool | Description |
|
|
11
11
|
|------|-------------|
|
|
12
|
-
| `
|
|
13
|
-
| `speech_to_text` | Transcribes an audio file into text
|
|
14
|
-
| `speech_to_speech` |
|
|
12
|
+
| `text_to_speech` | Converts text to speech and returns the generated audio data. |
|
|
13
|
+
| `speech_to_text` | Transcribes an audio file into text. |
|
|
14
|
+
| `speech_to_speech` | Converts speech from an audio source (URL or local path) to a different voice. |
|
|
15
|
+
| `get_history_items` | Returns a list of generated audio history items. |
|
|
16
|
+
| `get_history_item` | Retrieves a specific history item by ID. |
|
|
17
|
+
| `delete_history_item` | Deletes a history item by ID. |
|
|
18
|
+
| `get_history_item_audio` | Gets the audio for a history item. |
|
|
19
|
+
| `get_voices` | Lists all available voices. |
|
|
20
|
+
| `get_voice` | Gets details of a specific voice. |
|
|
21
|
+
| `delete_voice` | Deletes a voice by ID. |
|
|
22
|
+
| `get_voice_samples` | Gets samples for a specific voice. |
|
|
23
|
+
| `delete_sample` | Deletes a sample. |
|
|
24
|
+
| `convert_text_to_sound_effect` | Converts text to sound effects. |
|
|
25
|
+
| `convert_text_to_dialogue` | Converts a list of text and voice ID pairs into speech (dialogue) and returns synthesized audio. |
|
|
26
|
+
| `remix_voice` | Remixes an existing voice to create a new one based on a description. |
|
|
27
|
+
| `convert_text_to_music` | Generates music based on a text prompt. |
|
|
28
|
+
| `clone_voice` | Clones a voice from provided audio samples (URLs or local paths). |
|
|
29
|
+
| `design_voice` | Generates voice previews based on a text description. |
|
|
30
|
+
| `align_audio` | Aligns text to an audio file, returning timing information for characters and words. |
|
|
31
|
+
| `isolate_audio` | Removes background noise from audio. |
|
|
32
|
+
| `dub_file` | Dubs an audio file into another language. |
|
|
33
|
+
| `get_dubbing_project_metadata` | Gets metadata for a dubbing project. |
|
|
34
|
+
| `get_dubbed_file` | Downloads a dubbed file. |
|
|
35
|
+
| `get_models` | Lists available models. |
|
|
36
|
+
| `get_user_info` | Gets user information. |
|
|
37
|
+
| `get_user_subscription` | Gets user subscription details. |
|
|
38
|
+
| `get_usage` | Gets usage statistics. Defaults to the last 30 days if dates are not provided. |
|