universal-mcp-applications 0.1.39rc8__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/airtable/app.py +13 -13
- universal_mcp/applications/apollo/app.py +2 -2
- universal_mcp/applications/aws_s3/app.py +30 -19
- universal_mcp/applications/browser_use/app.py +10 -7
- universal_mcp/applications/contentful/app.py +4 -4
- universal_mcp/applications/crustdata/app.py +2 -2
- universal_mcp/applications/e2b/app.py +3 -4
- universal_mcp/applications/elevenlabs/README.md +27 -3
- universal_mcp/applications/elevenlabs/app.py +753 -48
- universal_mcp/applications/exa/app.py +18 -11
- universal_mcp/applications/falai/README.md +5 -7
- universal_mcp/applications/falai/app.py +160 -159
- universal_mcp/applications/firecrawl/app.py +14 -15
- universal_mcp/applications/ghost_content/app.py +4 -4
- universal_mcp/applications/github/app.py +2 -2
- universal_mcp/applications/gong/app.py +2 -2
- universal_mcp/applications/google_docs/README.md +15 -14
- universal_mcp/applications/google_docs/app.py +5 -4
- universal_mcp/applications/google_gemini/app.py +61 -17
- universal_mcp/applications/google_sheet/README.md +2 -1
- universal_mcp/applications/google_sheet/app.py +55 -0
- universal_mcp/applications/heygen/README.md +10 -32
- universal_mcp/applications/heygen/app.py +350 -744
- universal_mcp/applications/klaviyo/app.py +2 -2
- universal_mcp/applications/linkedin/README.md +14 -2
- universal_mcp/applications/linkedin/app.py +411 -38
- universal_mcp/applications/ms_teams/app.py +420 -1285
- universal_mcp/applications/notion/app.py +2 -2
- universal_mcp/applications/openai/app.py +1 -1
- universal_mcp/applications/perplexity/app.py +6 -7
- universal_mcp/applications/reddit/app.py +4 -4
- universal_mcp/applications/resend/app.py +31 -32
- universal_mcp/applications/rocketlane/app.py +2 -2
- universal_mcp/applications/scraper/app.py +51 -21
- universal_mcp/applications/semrush/app.py +1 -1
- universal_mcp/applications/serpapi/app.py +8 -7
- universal_mcp/applications/shopify/app.py +5 -7
- universal_mcp/applications/shortcut/app.py +3 -2
- universal_mcp/applications/slack/app.py +2 -2
- universal_mcp/applications/twilio/app.py +14 -13
- {universal_mcp_applications-0.1.39rc8.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/METADATA +1 -1
- {universal_mcp_applications-0.1.39rc8.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/RECORD +45 -45
- {universal_mcp_applications-0.1.39rc8.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.39rc8.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/licenses/LICENSE +0 -0
|
@@ -40,7 +40,7 @@ class GoogleGeminiApp(APIApplication):
|
|
|
40
40
|
if self._genai_client is not None:
|
|
41
41
|
return self._genai_client
|
|
42
42
|
|
|
43
|
-
credentials = self.integration.
|
|
43
|
+
credentials = await self.integration.get_credentials_async()
|
|
44
44
|
api_key = (
|
|
45
45
|
credentials.get("api_key")
|
|
46
46
|
or credentials.get("API_KEY")
|
|
@@ -18,11 +18,11 @@ class AirtableApp(APIApplication):
|
|
|
18
18
|
def __init__(self, integration: Integration | None = None) -> None:
|
|
19
19
|
super().__init__(name="airtable", integration=integration)
|
|
20
20
|
|
|
21
|
-
def
|
|
21
|
+
async def get_client(self) -> Api:
|
|
22
22
|
"""Initializes and returns the pyairtable client after ensuring API key is set."""
|
|
23
23
|
if not self.integration:
|
|
24
24
|
raise ValueError("Integration is not set for AirtableApp.")
|
|
25
|
-
credentials = self.integration.
|
|
25
|
+
credentials = await self.integration.get_credentials_async()
|
|
26
26
|
api_key = credentials.get("api_key") or credentials.get("apiKey") or credentials.get("API_KEY")
|
|
27
27
|
if not api_key:
|
|
28
28
|
raise ValueError("Airtable API key is not configured in the integration.")
|
|
@@ -52,7 +52,7 @@ class AirtableApp(APIApplication):
|
|
|
52
52
|
list, base, important
|
|
53
53
|
"""
|
|
54
54
|
try:
|
|
55
|
-
client = self.
|
|
55
|
+
client = await self.get_client()
|
|
56
56
|
return client.bases()
|
|
57
57
|
except Exception as e:
|
|
58
58
|
return f"Error listing bases: {type(e).__name__} - {e}"
|
|
@@ -72,7 +72,7 @@ class AirtableApp(APIApplication):
|
|
|
72
72
|
list, table, important
|
|
73
73
|
"""
|
|
74
74
|
try:
|
|
75
|
-
client = self.
|
|
75
|
+
client = await self.get_client()
|
|
76
76
|
base = client.base(base_id)
|
|
77
77
|
return base.tables()
|
|
78
78
|
except Exception as e:
|
|
@@ -98,7 +98,7 @@ class AirtableApp(APIApplication):
|
|
|
98
98
|
get, record, important
|
|
99
99
|
"""
|
|
100
100
|
try:
|
|
101
|
-
client = self.
|
|
101
|
+
client = await self.get_client()
|
|
102
102
|
table = client.table(base_id, table_id_or_name)
|
|
103
103
|
pyairtable_params = self._prepare_pyairtable_params(options)
|
|
104
104
|
return table.get(record_id, **pyairtable_params)
|
|
@@ -125,7 +125,7 @@ class AirtableApp(APIApplication):
|
|
|
125
125
|
list, record, important
|
|
126
126
|
"""
|
|
127
127
|
try:
|
|
128
|
-
client = self.
|
|
128
|
+
client = await self.get_client()
|
|
129
129
|
table = client.table(base_id, table_id_or_name)
|
|
130
130
|
pyairtable_params = self._prepare_pyairtable_params(options)
|
|
131
131
|
if "formula" in pyairtable_params and isinstance(pyairtable_params["formula"], Formula):
|
|
@@ -154,7 +154,7 @@ class AirtableApp(APIApplication):
|
|
|
154
154
|
create, record, important
|
|
155
155
|
"""
|
|
156
156
|
try:
|
|
157
|
-
client = self.
|
|
157
|
+
client = await self.get_client()
|
|
158
158
|
table = client.table(base_id, table_id_or_name)
|
|
159
159
|
prepared_options = self._prepare_pyairtable_params(options)
|
|
160
160
|
prepared_options.get("typecast", False)
|
|
@@ -191,7 +191,7 @@ class AirtableApp(APIApplication):
|
|
|
191
191
|
update, record
|
|
192
192
|
"""
|
|
193
193
|
try:
|
|
194
|
-
client = self.
|
|
194
|
+
client = await self.get_client()
|
|
195
195
|
table = client.table(base_id, table_id_or_name)
|
|
196
196
|
prepared_options = self._prepare_pyairtable_params(options)
|
|
197
197
|
call_kwargs = {}
|
|
@@ -222,7 +222,7 @@ class AirtableApp(APIApplication):
|
|
|
222
222
|
delete, record
|
|
223
223
|
"""
|
|
224
224
|
try:
|
|
225
|
-
client = self.
|
|
225
|
+
client = await self.get_client()
|
|
226
226
|
table = client.table(base_id, table_id_or_name)
|
|
227
227
|
return table.delete(record_id)
|
|
228
228
|
except Exception as e:
|
|
@@ -250,7 +250,7 @@ class AirtableApp(APIApplication):
|
|
|
250
250
|
create, record, batch
|
|
251
251
|
"""
|
|
252
252
|
try:
|
|
253
|
-
client = self.
|
|
253
|
+
client = await self.get_client()
|
|
254
254
|
table = client.table(base_id, table_id_or_name)
|
|
255
255
|
prepared_options = self._prepare_pyairtable_params(options)
|
|
256
256
|
call_kwargs = {}
|
|
@@ -284,7 +284,7 @@ class AirtableApp(APIApplication):
|
|
|
284
284
|
update, record, batch
|
|
285
285
|
"""
|
|
286
286
|
try:
|
|
287
|
-
client = self.
|
|
287
|
+
client = await self.get_client()
|
|
288
288
|
table = client.table(base_id, table_id_or_name)
|
|
289
289
|
prepared_options = self._prepare_pyairtable_params(options)
|
|
290
290
|
call_kwargs = {}
|
|
@@ -317,7 +317,7 @@ class AirtableApp(APIApplication):
|
|
|
317
317
|
delete, record, batch
|
|
318
318
|
"""
|
|
319
319
|
try:
|
|
320
|
-
client = self.
|
|
320
|
+
client = await self.get_client()
|
|
321
321
|
table = client.table(base_id, table_id_or_name)
|
|
322
322
|
return table.batch_delete(record_ids)
|
|
323
323
|
except Exception as e:
|
|
@@ -349,7 +349,7 @@ class AirtableApp(APIApplication):
|
|
|
349
349
|
create, update, record, batch, upsert
|
|
350
350
|
"""
|
|
351
351
|
try:
|
|
352
|
-
client = self.
|
|
352
|
+
client = await self.get_client()
|
|
353
353
|
table = client.table(base_id, table_id_or_name)
|
|
354
354
|
prepared_options = self._prepare_pyairtable_params(options)
|
|
355
355
|
call_kwargs = {}
|
|
@@ -9,7 +9,7 @@ class ApolloApp(APIApplication):
|
|
|
9
9
|
super().__init__(name="apollo", integration=integration, **kwargs)
|
|
10
10
|
self.base_url = "https://api.apollo.io/api/v1"
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
async def _aget_headers(self) -> dict[str, str]:
|
|
13
13
|
"""
|
|
14
14
|
Get the headers for Apollo API requests.
|
|
15
15
|
Overrides the base class method to use X-Api-Key.
|
|
@@ -17,7 +17,7 @@ class ApolloApp(APIApplication):
|
|
|
17
17
|
if not self.integration:
|
|
18
18
|
logger.warning("ApolloApp: No integration configured, returning empty headers.")
|
|
19
19
|
return {}
|
|
20
|
-
credentials = self.integration.
|
|
20
|
+
credentials = await self.integration.get_credentials_async()
|
|
21
21
|
api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
|
|
22
22
|
if not api_key:
|
|
23
23
|
logger.error("ApolloApp: API key not found in integration credentials for Apollo.")
|
|
@@ -25,15 +25,14 @@ class AwsS3App(BaseApplication):
|
|
|
25
25
|
self._client = client
|
|
26
26
|
self.integration = integration
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
def client(self):
|
|
28
|
+
async def get_client(self):
|
|
30
29
|
"""
|
|
31
30
|
Lazily initializes and returns a cached Boto3 S3 client instance. It retrieves authentication credentials from the associated `integration` object. This property is the core mechanism used by all other methods in the class to interact with AWS S3, raising an error if the integration is not set.
|
|
32
31
|
"""
|
|
33
32
|
if not self.integration:
|
|
34
33
|
raise ValueError("Integration not initialized")
|
|
35
34
|
if not self._client:
|
|
36
|
-
credentials = self.integration.
|
|
35
|
+
credentials = await self.integration.get_credentials_async()
|
|
37
36
|
credentials = {
|
|
38
37
|
"aws_access_key_id": credentials.get("access_key_id") or credentials.get("username"),
|
|
39
38
|
"aws_secret_access_key": credentials.get("secret_access_key") or credentials.get("password"),
|
|
@@ -42,14 +41,15 @@ class AwsS3App(BaseApplication):
|
|
|
42
41
|
self._client = boto3.client("s3", **credentials)
|
|
43
42
|
return self._client
|
|
44
43
|
|
|
45
|
-
def list_buckets(self) -> list[str]:
|
|
44
|
+
async def list_buckets(self) -> list[str]:
|
|
46
45
|
"""
|
|
47
46
|
Retrieves all S3 buckets accessible by the configured AWS credentials. It calls the S3 API's list_buckets operation and processes the response to return a simple list containing just the names of the buckets.
|
|
48
47
|
|
|
49
48
|
Returns:
|
|
50
49
|
List[str]: A list of bucket names.
|
|
51
50
|
"""
|
|
52
|
-
|
|
51
|
+
client = await self.get_client()
|
|
52
|
+
response = await client.list_buckets()
|
|
53
53
|
return [bucket["Name"] for bucket in response["Buckets"]]
|
|
54
54
|
|
|
55
55
|
async def create_bucket(self, bucket_name: str, region: str | None = None) -> bool:
|
|
@@ -66,10 +66,11 @@ class AwsS3App(BaseApplication):
|
|
|
66
66
|
important
|
|
67
67
|
"""
|
|
68
68
|
try:
|
|
69
|
+
client = await self.get_client()
|
|
69
70
|
if region:
|
|
70
|
-
|
|
71
|
+
await client.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={"LocationConstraint": region})
|
|
71
72
|
else:
|
|
72
|
-
|
|
73
|
+
await client.create_bucket(Bucket=bucket_name)
|
|
73
74
|
return True
|
|
74
75
|
except ClientError:
|
|
75
76
|
return False
|
|
@@ -87,7 +88,8 @@ class AwsS3App(BaseApplication):
|
|
|
87
88
|
important
|
|
88
89
|
"""
|
|
89
90
|
try:
|
|
90
|
-
self.
|
|
91
|
+
client = await self.get_client()
|
|
92
|
+
await client.delete_bucket(Bucket=bucket_name)
|
|
91
93
|
return True
|
|
92
94
|
except ClientError:
|
|
93
95
|
return False
|
|
@@ -105,7 +107,8 @@ class AwsS3App(BaseApplication):
|
|
|
105
107
|
important
|
|
106
108
|
"""
|
|
107
109
|
try:
|
|
108
|
-
|
|
110
|
+
client = await self.get_client()
|
|
111
|
+
response = await client.get_bucket_policy(Bucket=bucket_name)
|
|
109
112
|
return json.loads(response["Policy"])
|
|
110
113
|
except ClientError as e:
|
|
111
114
|
return {"error": str(e)}
|
|
@@ -124,7 +127,8 @@ class AwsS3App(BaseApplication):
|
|
|
124
127
|
important
|
|
125
128
|
"""
|
|
126
129
|
try:
|
|
127
|
-
|
|
130
|
+
client = await self.get_client()
|
|
131
|
+
await client.put_bucket_policy(Bucket=bucket_name, Policy=json.dumps(policy))
|
|
128
132
|
return True
|
|
129
133
|
except ClientError:
|
|
130
134
|
return False
|
|
@@ -142,7 +146,7 @@ class AwsS3App(BaseApplication):
|
|
|
142
146
|
Tags:
|
|
143
147
|
important
|
|
144
148
|
"""
|
|
145
|
-
paginator = self.
|
|
149
|
+
paginator = (await self.get_client()).get_paginator("list_objects_v2")
|
|
146
150
|
operation_parameters = {"Bucket": bucket_name}
|
|
147
151
|
if prefix:
|
|
148
152
|
operation_parameters["Prefix"] = prefix
|
|
@@ -173,7 +177,7 @@ class AwsS3App(BaseApplication):
|
|
|
173
177
|
key = f"{parent_prefix.rstrip('/')}/{prefix_name}/"
|
|
174
178
|
else:
|
|
175
179
|
key = f"{prefix_name}/"
|
|
176
|
-
self.
|
|
180
|
+
await (await self.get_client()).put_object(Bucket=bucket_name, Key=key)
|
|
177
181
|
return True
|
|
178
182
|
|
|
179
183
|
async def list_objects(self, bucket_name: str, prefix: str) -> list[dict[str, Any]]:
|
|
@@ -189,7 +193,8 @@ class AwsS3App(BaseApplication):
|
|
|
189
193
|
Tags:
|
|
190
194
|
important
|
|
191
195
|
"""
|
|
192
|
-
|
|
196
|
+
client = await self.get_client()
|
|
197
|
+
paginator = client.get_paginator("list_objects_v2")
|
|
193
198
|
operation_parameters = {"Bucket": bucket_name, "Prefix": prefix}
|
|
194
199
|
objects = []
|
|
195
200
|
for page in paginator.paginate(**operation_parameters):
|
|
@@ -223,7 +228,8 @@ class AwsS3App(BaseApplication):
|
|
|
223
228
|
important
|
|
224
229
|
"""
|
|
225
230
|
key = f"{prefix.rstrip('/')}/{object_name}" if prefix else object_name
|
|
226
|
-
|
|
231
|
+
client = await self.get_client()
|
|
232
|
+
await client.put_object(Bucket=bucket_name, Key=key, Body=content.encode("utf-8"))
|
|
227
233
|
return True
|
|
228
234
|
|
|
229
235
|
async def put_object_from_base64(self, bucket_name: str, prefix: str, object_name: str, base64_content: str) -> bool:
|
|
@@ -244,7 +250,8 @@ class AwsS3App(BaseApplication):
|
|
|
244
250
|
try:
|
|
245
251
|
key = f"{prefix.rstrip('/')}/{object_name}" if prefix else object_name
|
|
246
252
|
content = base64.b64decode(base64_content)
|
|
247
|
-
|
|
253
|
+
client = await self.get_client()
|
|
254
|
+
await client.put_object(Bucket=bucket_name, Key=key, Body=content)
|
|
248
255
|
return True
|
|
249
256
|
except Exception:
|
|
250
257
|
return False
|
|
@@ -263,7 +270,8 @@ class AwsS3App(BaseApplication):
|
|
|
263
270
|
important
|
|
264
271
|
"""
|
|
265
272
|
try:
|
|
266
|
-
|
|
273
|
+
client = await self.get_client()
|
|
274
|
+
obj = await client.get_object(Bucket=bucket_name, Key=key)
|
|
267
275
|
content = obj["Body"].read()
|
|
268
276
|
is_text_file = key.lower().endswith((".txt", ".csv", ".json", ".xml", ".html", ".md", ".js", ".css", ".py"))
|
|
269
277
|
content_dict = (
|
|
@@ -287,7 +295,8 @@ class AwsS3App(BaseApplication):
|
|
|
287
295
|
important
|
|
288
296
|
"""
|
|
289
297
|
try:
|
|
290
|
-
|
|
298
|
+
client = await self.get_client()
|
|
299
|
+
response = await client.head_object(Bucket=bucket_name, Key=key)
|
|
291
300
|
return {
|
|
292
301
|
"key": key,
|
|
293
302
|
"name": key.split("/")[-1],
|
|
@@ -375,7 +384,8 @@ class AwsS3App(BaseApplication):
|
|
|
375
384
|
"""
|
|
376
385
|
try:
|
|
377
386
|
delete_dict = {"Objects": [{"Key": key} for key in keys]}
|
|
378
|
-
|
|
387
|
+
client = await self.get_client()
|
|
388
|
+
response = await client.delete_objects(Bucket=bucket_name, Delete=delete_dict)
|
|
379
389
|
return {
|
|
380
390
|
"deleted": [obj.get("Key") for obj in response.get("Deleted", [])],
|
|
381
391
|
"errors": [obj for obj in response.get("Errors", [])],
|
|
@@ -400,7 +410,8 @@ class AwsS3App(BaseApplication):
|
|
|
400
410
|
"""
|
|
401
411
|
try:
|
|
402
412
|
method_map = {"GET": "get_object", "PUT": "put_object", "DELETE": "delete_object"}
|
|
403
|
-
|
|
413
|
+
client = await self.get_client()
|
|
414
|
+
response = await client.generate_presigned_url(
|
|
404
415
|
method_map.get(http_method.upper(), "get_object"), Params={"Bucket": bucket_name, "Key": key}, ExpiresIn=expiration
|
|
405
416
|
)
|
|
406
417
|
return response
|
|
@@ -11,13 +11,12 @@ class BrowserUseApp(APIApplication):
|
|
|
11
11
|
super().__init__(name="browser_use", integration=integration, **kwargs)
|
|
12
12
|
self._browser_client = None
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
def browser_client(self) -> AsyncBrowserUse:
|
|
14
|
+
async def get_client(self) -> AsyncBrowserUse:
|
|
16
15
|
if self._browser_client is not None:
|
|
17
16
|
return self._browser_client
|
|
18
17
|
if not self.integration:
|
|
19
18
|
raise ValueError("Integration is required but not provided")
|
|
20
|
-
credentials = self.integration.
|
|
19
|
+
credentials = await self.integration.get_credentials_async()
|
|
21
20
|
api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
|
|
22
21
|
if not api_key:
|
|
23
22
|
raise ValueError("API key not found in integration credentials")
|
|
@@ -61,7 +60,8 @@ class BrowserUseApp(APIApplication):
|
|
|
61
60
|
Tags:
|
|
62
61
|
browser, automation, background, task, web, research, create, important
|
|
63
62
|
"""
|
|
64
|
-
|
|
63
|
+
client = await self.get_client()
|
|
64
|
+
created_task = await client.tasks.create_task(
|
|
65
65
|
llm=llm, task=task, max_steps=max_steps, session_id=session_id
|
|
66
66
|
)
|
|
67
67
|
|
|
@@ -83,7 +83,8 @@ class BrowserUseApp(APIApplication):
|
|
|
83
83
|
Tags:
|
|
84
84
|
status, poll, browser, task, monitoring, output, important
|
|
85
85
|
"""
|
|
86
|
-
|
|
86
|
+
client = await self.get_client()
|
|
87
|
+
task = await client.tasks.get_task(task_id)
|
|
87
88
|
return task.model_dump()
|
|
88
89
|
|
|
89
90
|
async def list_tasks(
|
|
@@ -102,7 +103,8 @@ class BrowserUseApp(APIApplication):
|
|
|
102
103
|
Tags:
|
|
103
104
|
list, history, browser, tasks, audit
|
|
104
105
|
"""
|
|
105
|
-
|
|
106
|
+
client = await self.get_client()
|
|
107
|
+
tasks = await client.tasks.list_tasks(page_size=page_size)
|
|
106
108
|
return tasks.model_dump()
|
|
107
109
|
|
|
108
110
|
async def stop_task(
|
|
@@ -121,7 +123,8 @@ class BrowserUseApp(APIApplication):
|
|
|
121
123
|
Tags:
|
|
122
124
|
stop, cancel, browser, task, control
|
|
123
125
|
"""
|
|
124
|
-
|
|
126
|
+
client = await self.get_client()
|
|
127
|
+
updated_task = await client.tasks.update_task(task_id, action="stop")
|
|
125
128
|
return updated_task.model_dump()
|
|
126
129
|
|
|
127
130
|
def list_tools(self):
|
|
@@ -16,7 +16,7 @@ class ContentfulApp(GraphQLApplication):
|
|
|
16
16
|
default_base_url = "https://graphql.contentful.com"
|
|
17
17
|
super().__init__(name="contentful", base_url=default_base_url, integration=integration, **kwargs)
|
|
18
18
|
|
|
19
|
-
def _load_credentials_and_construct_url(self) -> bool:
|
|
19
|
+
async def _load_credentials_and_construct_url(self) -> bool:
|
|
20
20
|
"""
|
|
21
21
|
Loads credentials from the integration, constructs the precise API URL,
|
|
22
22
|
and prepares the instance for API calls. Runs only once.
|
|
@@ -32,7 +32,7 @@ class ContentfulApp(GraphQLApplication):
|
|
|
32
32
|
self._credentials_loaded = True
|
|
33
33
|
return False
|
|
34
34
|
try:
|
|
35
|
-
credentials = self.integration.
|
|
35
|
+
credentials = await self.integration.get_credentials_async()
|
|
36
36
|
except NotAuthorizedError as e:
|
|
37
37
|
logger.error(f"Authorization required or credentials unavailable for Contentful: {e.message}")
|
|
38
38
|
self._credentials_loaded = True
|
|
@@ -85,10 +85,10 @@ class ContentfulApp(GraphQLApplication):
|
|
|
85
85
|
return s[0].upper() + s[1:] if len(s) > 1 else s.upper()
|
|
86
86
|
return "".join((word.capitalize() for word in parts))
|
|
87
87
|
|
|
88
|
-
def _ensure_loaded(self) -> bool:
|
|
88
|
+
async def _ensure_loaded(self) -> bool:
|
|
89
89
|
"""Internal helper to trigger lazy loading and check status."""
|
|
90
90
|
if not self._credentials_loaded:
|
|
91
|
-
return self._load_credentials_and_construct_url()
|
|
91
|
+
return await self._load_credentials_and_construct_url()
|
|
92
92
|
return bool(self.base_url and self.space_id and self._access_token)
|
|
93
93
|
|
|
94
94
|
async def get_entry(
|
|
@@ -8,8 +8,8 @@ class CrustdataApp(APIApplication):
|
|
|
8
8
|
super().__init__(name="crustdata", integration=integration, **kwargs)
|
|
9
9
|
self.base_url = "https://api.crustdata.com"
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
api_key = self.integration.
|
|
11
|
+
async def _aget_headers(self) -> dict[str, Any]:
|
|
12
|
+
api_key = await self.integration.get_credentials_async().get("api_key")
|
|
13
13
|
return {"Authorization": f"Token {api_key}", "Content-Type": "application/json", "Accept": "application/json"}
|
|
14
14
|
|
|
15
15
|
async def screen_companies(self, metrics, filters, offset, count, sorts) -> dict[str, Any]:
|
|
@@ -25,8 +25,7 @@ class E2bApp(APIApplication):
|
|
|
25
25
|
if Sandbox is None:
|
|
26
26
|
logger.warning("E2B Sandbox SDK is not available. E2B tools will not function.")
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
def e2b_api_key(self) -> str:
|
|
28
|
+
async def get_e2b_api_key(self) -> str:
|
|
30
29
|
"""
|
|
31
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.
|
|
32
31
|
"""
|
|
@@ -35,7 +34,7 @@ class E2bApp(APIApplication):
|
|
|
35
34
|
logger.error("E2B App: Integration not configured.")
|
|
36
35
|
raise NotAuthorizedError("Integration not configured for E2B App. Cannot retrieve API key.")
|
|
37
36
|
try:
|
|
38
|
-
credentials = self.integration.
|
|
37
|
+
credentials = await self.integration.get_credentials_async()
|
|
39
38
|
except NotAuthorizedError as e:
|
|
40
39
|
logger.error(f"E2B App: Authorization error when fetching credentials: {e.message}")
|
|
41
40
|
raise
|
|
@@ -111,7 +110,7 @@ class E2bApp(APIApplication):
|
|
|
111
110
|
raise ValueError("Provided code must be a non-empty string.")
|
|
112
111
|
try:
|
|
113
112
|
logger.info("Attempting to execute Python code in E2B Sandbox.")
|
|
114
|
-
os.environ["E2B_API_KEY"] = self.
|
|
113
|
+
os.environ["E2B_API_KEY"] = await self.get_e2b_api_key()
|
|
115
114
|
with Sandbox.create() as sandbox:
|
|
116
115
|
logger.info("E2B Sandbox initialized. Running code.")
|
|
117
116
|
execution = sandbox.run_code(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. |
|