dhisana 0.0.1.dev233__tar.gz → 0.0.1.dev234__tar.gz
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.
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/PKG-INFO +1 -1
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/setup.py +1 -1
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/test_connect.py +347 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/README.md +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/setup.cfg +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/schemas/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/schemas/common.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/schemas/sales.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/add_mapping.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/apollo_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/built_with_api_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/cache_output_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/cache_output_tools_local.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_email_validity_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_for_intent_signal.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/clay_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/clean_properties.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/company_utils.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_salesnav_query.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_search_query.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/composite_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/dataframe_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/domain_parser.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/email_body_utils.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/email_parse_helpers.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/email_provider.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/enrich_lead_information.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/fetch_openai_config.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/field_validators.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/g2_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_content.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_email.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_email_response.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_flow.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/google_custom_search.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/google_oauth_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/google_workspace_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/hubspot_clearbit.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/instantly_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/lusha_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/mailgun_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/microsoft365_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openai_helpers.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/profile.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/proxy_curl_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/proxycurl_search_leads.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/research_lead.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/search_router.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/search_router_jobs.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/sendgrid_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serarch_router_local_business.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_google_jobs.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_google_search.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_local_business_search.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_search_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serperdev_google_jobs.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serperdev_local_business.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serperdev_search.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/smtp_email_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/trasform_json.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/web_download_parse_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/workflow_code_model.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/zoominfo_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/agent.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/flow.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/test.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/SOURCES.txt +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_agent_tools.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_apollo_company_search.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_apollo_lead_search.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_connectivity.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_email_body_utils.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_google_document.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_hubspot_call_logs.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_linkedin_serper.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_mcp_connectivity.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_proxycurl_get_company_search_id.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_proxycurl_job_count.py +0 -0
- {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_structured_output_with_mcp.py +0 -0
|
@@ -1263,6 +1263,41 @@ async def test_firecrawl(api_key: str) -> Dict[str, Any]:
|
|
|
1263
1263
|
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1264
1264
|
|
|
1265
1265
|
|
|
1266
|
+
async def test_scraperapi(api_key: str) -> Dict[str, Any]:
|
|
1267
|
+
"""Connectivity check for ScraperAPI using a simple NYTimes scrape."""
|
|
1268
|
+
url = "https://api.scraperapi.com/"
|
|
1269
|
+
params = {
|
|
1270
|
+
"api_key": api_key,
|
|
1271
|
+
"url": "https://example.com/", # lightweight public page to minimize credit usage
|
|
1272
|
+
"output_format": "markdown",
|
|
1273
|
+
}
|
|
1274
|
+
try:
|
|
1275
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1276
|
+
async with session.get(url, params=params) as response:
|
|
1277
|
+
status = response.status
|
|
1278
|
+
body_text = await response.text()
|
|
1279
|
+
|
|
1280
|
+
if status != 200:
|
|
1281
|
+
snippet = body_text[:200] if body_text else None
|
|
1282
|
+
return {
|
|
1283
|
+
"success": False,
|
|
1284
|
+
"status_code": status,
|
|
1285
|
+
"error_message": snippet or f"Non-200 from ScraperAPI: {status}",
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
if not body_text:
|
|
1289
|
+
return {
|
|
1290
|
+
"success": False,
|
|
1291
|
+
"status_code": status,
|
|
1292
|
+
"error_message": "ScraperAPI returned an empty response.",
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1296
|
+
except Exception as exc:
|
|
1297
|
+
logger.error(f"ScraperAPI connectivity test failed: {exc}")
|
|
1298
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1299
|
+
|
|
1300
|
+
|
|
1266
1301
|
async def test_youtube(api_key: str) -> Dict[str, Any]:
|
|
1267
1302
|
"""
|
|
1268
1303
|
Tests YouTube Data API v3 by making a simple search request.
|
|
@@ -1341,6 +1376,276 @@ async def test_youtube(api_key: str) -> Dict[str, Any]:
|
|
|
1341
1376
|
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1342
1377
|
|
|
1343
1378
|
|
|
1379
|
+
async def test_orum(api_key: str) -> Dict[str, Any]:
|
|
1380
|
+
"""
|
|
1381
|
+
Validate an Orum API key by calling a lightweight authenticated endpoint.
|
|
1382
|
+
|
|
1383
|
+
The base URL can be overridden with ORUM_API_BASE_URL if needed.
|
|
1384
|
+
"""
|
|
1385
|
+
base_url = os.getenv("ORUM_API_BASE_URL", "https://api.orum.com")
|
|
1386
|
+
url = f"{base_url.rstrip('/')}/api/v1/users/me"
|
|
1387
|
+
headers = {
|
|
1388
|
+
"Authorization": f"Bearer {api_key}",
|
|
1389
|
+
"Accept": "application/json",
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
try:
|
|
1393
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1394
|
+
async with session.get(url, headers=headers) as response:
|
|
1395
|
+
status = response.status
|
|
1396
|
+
data = await safe_json(response)
|
|
1397
|
+
|
|
1398
|
+
if status == 200:
|
|
1399
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1400
|
+
|
|
1401
|
+
message = None
|
|
1402
|
+
if isinstance(data, dict):
|
|
1403
|
+
message = data.get("message") or data.get("error") or data.get("detail")
|
|
1404
|
+
return {
|
|
1405
|
+
"success": False,
|
|
1406
|
+
"status_code": status,
|
|
1407
|
+
"error_message": message or f"Orum responded with {status}",
|
|
1408
|
+
}
|
|
1409
|
+
except Exception as exc:
|
|
1410
|
+
logger.error(f"Orum connectivity test failed: {exc}")
|
|
1411
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
async def test_aircall(app_id: str, api_token: str) -> Dict[str, Any]:
|
|
1415
|
+
"""
|
|
1416
|
+
Validate Aircall credentials via a lightweight authenticated call.
|
|
1417
|
+
Uses HTTP Basic Auth (app_id:api_token).
|
|
1418
|
+
"""
|
|
1419
|
+
url = "https://api.aircall.io/v1/users"
|
|
1420
|
+
params = {"per_page": 1}
|
|
1421
|
+
|
|
1422
|
+
try:
|
|
1423
|
+
auth = aiohttp.BasicAuth(app_id, api_token)
|
|
1424
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10), auth=auth) as session:
|
|
1425
|
+
async with session.get(url, params=params) as response:
|
|
1426
|
+
status = response.status
|
|
1427
|
+
data = await safe_json(response)
|
|
1428
|
+
|
|
1429
|
+
if status == 200 and isinstance(data, dict) and "users" in data:
|
|
1430
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1431
|
+
|
|
1432
|
+
message = None
|
|
1433
|
+
if isinstance(data, dict):
|
|
1434
|
+
message = data.get("message") or data.get("error")
|
|
1435
|
+
return {
|
|
1436
|
+
"success": False,
|
|
1437
|
+
"status_code": status,
|
|
1438
|
+
"error_message": message or f"Aircall responded with {status}",
|
|
1439
|
+
}
|
|
1440
|
+
except Exception as exc:
|
|
1441
|
+
logger.error(f"Aircall connectivity test failed: {exc}")
|
|
1442
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
async def test_ringover(api_key: str) -> Dict[str, Any]:
|
|
1446
|
+
"""
|
|
1447
|
+
Validate Ringover API key using a minimal authenticated request.
|
|
1448
|
+
"""
|
|
1449
|
+
base_url = os.getenv("RINGOVER_API_BASE_URL", "https://public-api.ringover.com")
|
|
1450
|
+
url = f"{base_url.rstrip('/')}/v2/users"
|
|
1451
|
+
headers = {
|
|
1452
|
+
"X-API-KEY": api_key,
|
|
1453
|
+
"Accept": "application/json",
|
|
1454
|
+
}
|
|
1455
|
+
params = {"limit": 1}
|
|
1456
|
+
|
|
1457
|
+
try:
|
|
1458
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1459
|
+
async with session.get(url, headers=headers, params=params) as response:
|
|
1460
|
+
status = response.status
|
|
1461
|
+
data = await safe_json(response)
|
|
1462
|
+
|
|
1463
|
+
if status == 200:
|
|
1464
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1465
|
+
|
|
1466
|
+
message = None
|
|
1467
|
+
if isinstance(data, dict):
|
|
1468
|
+
message = data.get("message") or data.get("error") or data.get("detail")
|
|
1469
|
+
return {
|
|
1470
|
+
"success": False,
|
|
1471
|
+
"status_code": status,
|
|
1472
|
+
"error_message": message or f"Ringover responded with {status}",
|
|
1473
|
+
}
|
|
1474
|
+
except Exception as exc:
|
|
1475
|
+
logger.error(f"Ringover connectivity test failed: {exc}")
|
|
1476
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1477
|
+
|
|
1478
|
+
|
|
1479
|
+
async def test_dialpad(client_id: str, client_secret: str) -> Dict[str, Any]:
|
|
1480
|
+
"""
|
|
1481
|
+
Validate Dialpad client credentials via client_credentials token exchange, then whoami.
|
|
1482
|
+
"""
|
|
1483
|
+
base_url = os.getenv("DIALPAD_API_BASE_URL", "https://dialpad.com")
|
|
1484
|
+
token_url = f"{base_url.rstrip('/')}/oauth/token"
|
|
1485
|
+
whoami_url = f"{base_url.rstrip('/')}/api/v2/whoami"
|
|
1486
|
+
|
|
1487
|
+
try:
|
|
1488
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1489
|
+
token_resp = await session.post(
|
|
1490
|
+
token_url,
|
|
1491
|
+
data={
|
|
1492
|
+
"grant_type": "client_credentials",
|
|
1493
|
+
"client_id": client_id,
|
|
1494
|
+
"client_secret": client_secret,
|
|
1495
|
+
},
|
|
1496
|
+
headers={"Accept": "application/json"},
|
|
1497
|
+
)
|
|
1498
|
+
token_status = token_resp.status
|
|
1499
|
+
token_data = await safe_json(token_resp)
|
|
1500
|
+
|
|
1501
|
+
access_token = None
|
|
1502
|
+
if isinstance(token_data, dict):
|
|
1503
|
+
access_token = token_data.get("access_token")
|
|
1504
|
+
|
|
1505
|
+
if token_status != 200 or not access_token:
|
|
1506
|
+
message = None
|
|
1507
|
+
if isinstance(token_data, dict):
|
|
1508
|
+
message = token_data.get("error_description") or token_data.get("error")
|
|
1509
|
+
return {
|
|
1510
|
+
"success": False,
|
|
1511
|
+
"status_code": token_status,
|
|
1512
|
+
"error_message": message or "Failed to obtain Dialpad access token.",
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
headers = {
|
|
1516
|
+
"Authorization": f"Bearer {access_token}",
|
|
1517
|
+
"Accept": "application/json",
|
|
1518
|
+
}
|
|
1519
|
+
async with session.get(whoami_url, headers=headers) as response:
|
|
1520
|
+
status = response.status
|
|
1521
|
+
data = await safe_json(response)
|
|
1522
|
+
|
|
1523
|
+
if status == 200:
|
|
1524
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1525
|
+
|
|
1526
|
+
message = None
|
|
1527
|
+
if isinstance(data, dict):
|
|
1528
|
+
message = data.get("message") or data.get("error") or data.get("detail")
|
|
1529
|
+
return {
|
|
1530
|
+
"success": False,
|
|
1531
|
+
"status_code": status,
|
|
1532
|
+
"error_message": message or f"Dialpad responded with {status}",
|
|
1533
|
+
}
|
|
1534
|
+
except Exception as exc:
|
|
1535
|
+
logger.error(f"Dialpad connectivity test failed: {exc}")
|
|
1536
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
async def test_nooks(api_key: str) -> Dict[str, Any]:
|
|
1540
|
+
"""
|
|
1541
|
+
Validate Nooks.ai API key via a simple authenticated call.
|
|
1542
|
+
"""
|
|
1543
|
+
base_url = os.getenv("NOOKS_API_BASE_URL", "https://api.nooks.ai")
|
|
1544
|
+
url = f"{base_url.rstrip('/')}/v1/users/me"
|
|
1545
|
+
headers = {
|
|
1546
|
+
"Authorization": f"Bearer {api_key}",
|
|
1547
|
+
"Accept": "application/json",
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
try:
|
|
1551
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1552
|
+
async with session.get(url, headers=headers) as response:
|
|
1553
|
+
status = response.status
|
|
1554
|
+
data = await safe_json(response)
|
|
1555
|
+
|
|
1556
|
+
if status == 200:
|
|
1557
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1558
|
+
|
|
1559
|
+
message = None
|
|
1560
|
+
if isinstance(data, dict):
|
|
1561
|
+
message = data.get("message") or data.get("error") or data.get("detail")
|
|
1562
|
+
return {
|
|
1563
|
+
"success": False,
|
|
1564
|
+
"status_code": status,
|
|
1565
|
+
"error_message": message or f"Nooks.ai responded with {status}",
|
|
1566
|
+
}
|
|
1567
|
+
except Exception as exc:
|
|
1568
|
+
logger.error(f"Nooks.ai connectivity test failed: {exc}")
|
|
1569
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
async def test_commonroom(api_key: str) -> Dict[str, Any]:
|
|
1573
|
+
"""Validate a Common Room API token via the token status endpoint."""
|
|
1574
|
+
url = "https://api.commonroom.io/community/v1/api-token-status"
|
|
1575
|
+
headers = {
|
|
1576
|
+
"Authorization": f"Bearer {api_key}",
|
|
1577
|
+
"Accept": "application/json",
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
try:
|
|
1581
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1582
|
+
async with session.get(url, headers=headers) as response:
|
|
1583
|
+
status = response.status
|
|
1584
|
+
data = await safe_json(response)
|
|
1585
|
+
|
|
1586
|
+
if status == 200:
|
|
1587
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1588
|
+
|
|
1589
|
+
message = None
|
|
1590
|
+
if isinstance(data, dict):
|
|
1591
|
+
message = (
|
|
1592
|
+
data.get("message")
|
|
1593
|
+
or data.get("reason")
|
|
1594
|
+
or data.get("error")
|
|
1595
|
+
or data.get("docs")
|
|
1596
|
+
)
|
|
1597
|
+
return {
|
|
1598
|
+
"success": False,
|
|
1599
|
+
"status_code": status,
|
|
1600
|
+
"error_message": message or f"Common Room responded with {status}",
|
|
1601
|
+
}
|
|
1602
|
+
except Exception as exc:
|
|
1603
|
+
logger.error(f"Common Room connectivity test failed: {exc}")
|
|
1604
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
async def test_scarf(api_key: str) -> Dict[str, Any]:
|
|
1608
|
+
"""
|
|
1609
|
+
Validate a Scarf API token via the lightweight /v2/search endpoint.
|
|
1610
|
+
|
|
1611
|
+
The endpoint requires only the bearer token and a simple query string.
|
|
1612
|
+
"""
|
|
1613
|
+
url = "https://api.scarf.sh/v2/search"
|
|
1614
|
+
headers = {
|
|
1615
|
+
"Authorization": f"Bearer {api_key}",
|
|
1616
|
+
"Content-Type": "application/json",
|
|
1617
|
+
}
|
|
1618
|
+
payload = {"query": "dhisana connectivity test"}
|
|
1619
|
+
|
|
1620
|
+
try:
|
|
1621
|
+
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
|
|
1622
|
+
async with session.post(url, headers=headers, json=payload) as response:
|
|
1623
|
+
status = response.status
|
|
1624
|
+
data = await safe_json(response)
|
|
1625
|
+
|
|
1626
|
+
if status != 200:
|
|
1627
|
+
message = None
|
|
1628
|
+
if isinstance(data, dict):
|
|
1629
|
+
message = data.get("message") or data.get("error") or data.get("detail")
|
|
1630
|
+
return {
|
|
1631
|
+
"success": False,
|
|
1632
|
+
"status_code": status,
|
|
1633
|
+
"error_message": message or f"Scarf responded with {status}",
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
if isinstance(data, dict) and "results" in data:
|
|
1637
|
+
return {"success": True, "status_code": status, "error_message": None}
|
|
1638
|
+
|
|
1639
|
+
return {
|
|
1640
|
+
"success": False,
|
|
1641
|
+
"status_code": status,
|
|
1642
|
+
"error_message": "Unexpected Scarf response payload.",
|
|
1643
|
+
}
|
|
1644
|
+
except Exception as exc:
|
|
1645
|
+
logger.error(f"Scarf connectivity test failed: {exc}")
|
|
1646
|
+
return {"success": False, "status_code": 0, "error_message": str(exc)}
|
|
1647
|
+
|
|
1648
|
+
|
|
1344
1649
|
###############################################################################
|
|
1345
1650
|
# DATAGMA CONNECTIVITY
|
|
1346
1651
|
###############################################################################
|
|
@@ -1427,6 +1732,13 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
|
|
|
1427
1732
|
"firefliesai": test_firefliesai,
|
|
1428
1733
|
"firecrawl": test_firecrawl,
|
|
1429
1734
|
"youtube": test_youtube,
|
|
1735
|
+
"orum": test_orum,
|
|
1736
|
+
"aircall": test_aircall, # handled specially to pass appId + apiToken
|
|
1737
|
+
"ringover": test_ringover,
|
|
1738
|
+
"dialpad": test_dialpad, # handled specially to pass client credentials
|
|
1739
|
+
"nooks": test_nooks,
|
|
1740
|
+
"commonRoom": test_commonroom,
|
|
1741
|
+
"scarf": test_scarf,
|
|
1430
1742
|
"salesforce": test_salesforce,
|
|
1431
1743
|
"clay": test_clay,
|
|
1432
1744
|
"posthog": test_posthog,
|
|
@@ -1435,6 +1747,7 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
|
|
|
1435
1747
|
"mailgun": test_mailgun,
|
|
1436
1748
|
"sendgrid": test_sendgrid,
|
|
1437
1749
|
"samgov": test_samgov,
|
|
1750
|
+
"scraperapi": test_scraperapi,
|
|
1438
1751
|
}
|
|
1439
1752
|
|
|
1440
1753
|
results: Dict[str, Dict[str, Any]] = {}
|
|
@@ -1603,6 +1916,40 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
|
|
|
1603
1916
|
)
|
|
1604
1917
|
continue
|
|
1605
1918
|
|
|
1919
|
+
# ------------------------------------------------------------------ #
|
|
1920
|
+
# Special-case: Aircall (app_id + api_token)
|
|
1921
|
+
# ------------------------------------------------------------------ #
|
|
1922
|
+
if tool_name == "aircall":
|
|
1923
|
+
app_id = next((c["value"] for c in config_entries if c["name"] == "apiId"), None)
|
|
1924
|
+
api_token = next((c["value"] for c in config_entries if c["name"] == "apiToken"), None)
|
|
1925
|
+
if not app_id or not api_token:
|
|
1926
|
+
results[tool_name] = {
|
|
1927
|
+
"success": False,
|
|
1928
|
+
"status_code": 0,
|
|
1929
|
+
"error_message": "Missing apiId or apiToken for Aircall.",
|
|
1930
|
+
}
|
|
1931
|
+
else:
|
|
1932
|
+
logger.info("Testing connectivity for Aircall…")
|
|
1933
|
+
results[tool_name] = await test_aircall(app_id, api_token)
|
|
1934
|
+
continue
|
|
1935
|
+
|
|
1936
|
+
# ------------------------------------------------------------------ #
|
|
1937
|
+
# Special-case: Dialpad (client credentials)
|
|
1938
|
+
# ------------------------------------------------------------------ #
|
|
1939
|
+
if tool_name == "dialpad":
|
|
1940
|
+
client_id = next((c["value"] for c in config_entries if c["name"] == "clientId"), None)
|
|
1941
|
+
client_secret = next((c["value"] for c in config_entries if c["name"] == "clientSecret"), None)
|
|
1942
|
+
if not client_id or not client_secret:
|
|
1943
|
+
results[tool_name] = {
|
|
1944
|
+
"success": False,
|
|
1945
|
+
"status_code": 0,
|
|
1946
|
+
"error_message": "Missing clientId or clientSecret for Dialpad.",
|
|
1947
|
+
}
|
|
1948
|
+
else:
|
|
1949
|
+
logger.info("Testing connectivity for Dialpad…")
|
|
1950
|
+
results[tool_name] = await test_dialpad(client_id, client_secret)
|
|
1951
|
+
continue
|
|
1952
|
+
|
|
1606
1953
|
# ------------------------------------------------------------------ #
|
|
1607
1954
|
# All other tools – expect an apiKey by default
|
|
1608
1955
|
# ------------------------------------------------------------------ #
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_email_validity_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_linkedin_url_validity.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_three_step_workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/extract_email_content_for_llm.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_linkedin_connect_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openai_assistant_and_file_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/openapi_tool.py
RENAMED
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/parse_linkedin_messages_txt.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serarch_router_local_business.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_local_business_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|