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.
Files changed (118) hide show
  1. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/PKG-INFO +1 -1
  2. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/setup.py +1 -1
  3. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/test_connect.py +347 -0
  4. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/PKG-INFO +1 -1
  5. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/README.md +0 -0
  6. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/pyproject.toml +0 -0
  7. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/setup.cfg +0 -0
  8. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/__init__.py +0 -0
  9. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/__init__.py +0 -0
  10. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/cli.py +0 -0
  11. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/datasets.py +0 -0
  12. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/models.py +0 -0
  13. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/cli/predictions.py +0 -0
  14. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/schemas/__init__.py +0 -0
  15. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/schemas/common.py +0 -0
  16. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/schemas/sales.py +0 -0
  17. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/ui/__init__.py +0 -0
  18. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/ui/components.py +0 -0
  19. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/__init__.py +0 -0
  20. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/add_mapping.py +0 -0
  21. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/agent_tools.py +0 -0
  22. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/apollo_tools.py +0 -0
  23. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  24. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/built_with_api_tools.py +0 -0
  25. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/cache_output_tools.py +0 -0
  26. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/cache_output_tools_local.py +0 -0
  27. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_email_validity_tools.py +0 -0
  28. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_for_intent_signal.py +0 -0
  29. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
  30. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/clay_tools.py +0 -0
  31. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/clean_properties.py +0 -0
  32. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/company_utils.py +0 -0
  33. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_salesnav_query.py +0 -0
  34. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_search_query.py +0 -0
  35. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
  36. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/composite_tools.py +0 -0
  37. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/dataframe_tools.py +0 -0
  38. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/domain_parser.py +0 -0
  39. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/email_body_utils.py +0 -0
  40. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/email_parse_helpers.py +0 -0
  41. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/email_provider.py +0 -0
  42. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/enrich_lead_information.py +0 -0
  43. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
  44. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/fetch_openai_config.py +0 -0
  45. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/field_validators.py +0 -0
  46. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/g2_tools.py +0 -0
  47. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_content.py +0 -0
  48. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_email.py +0 -0
  49. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_email_response.py +0 -0
  50. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_flow.py +0 -0
  51. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
  52. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
  53. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
  54. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
  55. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/google_custom_search.py +0 -0
  56. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/google_oauth_tools.py +0 -0
  57. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/google_workspace_tools.py +0 -0
  58. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/hubspot_clearbit.py +0 -0
  59. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
  60. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/instantly_tools.py +0 -0
  61. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/linkedin_crawler.py +0 -0
  62. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/lusha_tools.py +0 -0
  63. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/mailgun_tools.py +0 -0
  64. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/microsoft365_tools.py +0 -0
  65. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
  66. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openai_helpers.py +0 -0
  67. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  68. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
  69. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  70. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  71. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  72. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
  73. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/profile.py +0 -0
  74. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/proxy_curl_tools.py +0 -0
  75. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/proxycurl_search_leads.py +0 -0
  76. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/python_function_to_tools.py +0 -0
  77. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/research_lead.py +0 -0
  78. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
  79. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
  80. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/search_router.py +0 -0
  81. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/search_router_jobs.py +0 -0
  82. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/sendgrid_tools.py +0 -0
  83. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serarch_router_local_business.py +0 -0
  84. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
  85. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_google_jobs.py +0 -0
  86. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_google_search.py +0 -0
  87. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_local_business_search.py +0 -0
  88. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serpapi_search_tools.py +0 -0
  89. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serperdev_google_jobs.py +0 -0
  90. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serperdev_local_business.py +0 -0
  91. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/serperdev_search.py +0 -0
  92. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/smtp_email_tools.py +0 -0
  93. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/trasform_json.py +0 -0
  94. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/web_download_parse_tools.py +0 -0
  95. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/workflow_code_model.py +0 -0
  96. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/utils/zoominfo_tools.py +0 -0
  97. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/__init__.py +0 -0
  98. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/agent.py +0 -0
  99. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/flow.py +0 -0
  100. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/task.py +0 -0
  101. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana/workflow/test.py +0 -0
  102. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/SOURCES.txt +0 -0
  103. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/dependency_links.txt +0 -0
  104. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/entry_points.txt +0 -0
  105. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/requires.txt +0 -0
  106. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/src/dhisana.egg-info/top_level.txt +0 -0
  107. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_agent_tools.py +0 -0
  108. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_apollo_company_search.py +0 -0
  109. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_apollo_lead_search.py +0 -0
  110. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_connectivity.py +0 -0
  111. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_email_body_utils.py +0 -0
  112. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_google_document.py +0 -0
  113. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_hubspot_call_logs.py +0 -0
  114. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_linkedin_serper.py +0 -0
  115. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_mcp_connectivity.py +0 -0
  116. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_proxycurl_get_company_search_id.py +0 -0
  117. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_proxycurl_job_count.py +0 -0
  118. {dhisana-0.0.1.dev233 → dhisana-0.0.1.dev234}/tests/test_structured_output_with_mcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev233
3
+ Version: 0.0.1.dev234
4
4
  Summary: A Python SDK for Dhisana AI Platform
5
5
  Home-page: https://github.com/dhisana-ai/dhisana-python-sdk
6
6
  Author: Admin
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='dhisana',
5
- version='0.0.1-dev233',
5
+ version='0.0.1-dev234',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -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
  # ------------------------------------------------------------------ #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev233
3
+ Version: 0.0.1.dev234
4
4
  Summary: A Python SDK for Dhisana AI Platform
5
5
  Home-page: https://github.com/dhisana-ai/dhisana-python-sdk
6
6
  Author: Admin
File without changes
File without changes