dhisana 0.0.1.dev222__tar.gz → 0.0.1.dev224__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 (116) hide show
  1. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/PKG-INFO +1 -1
  2. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/setup.py +1 -1
  3. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/apollo_tools.py +2 -43
  4. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/test_connect.py +104 -0
  5. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana.egg-info/PKG-INFO +1 -1
  6. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_connectivity.py +16 -0
  7. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/README.md +0 -0
  8. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/pyproject.toml +0 -0
  9. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/setup.cfg +0 -0
  10. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/__init__.py +0 -0
  11. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/cli/__init__.py +0 -0
  12. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/cli/cli.py +0 -0
  13. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/cli/datasets.py +0 -0
  14. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/cli/models.py +0 -0
  15. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/cli/predictions.py +0 -0
  16. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/schemas/__init__.py +0 -0
  17. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/schemas/common.py +0 -0
  18. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/schemas/sales.py +0 -0
  19. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/ui/__init__.py +0 -0
  20. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/ui/components.py +0 -0
  21. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/__init__.py +0 -0
  22. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/add_mapping.py +0 -0
  23. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/agent_tools.py +0 -0
  24. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  25. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/built_with_api_tools.py +0 -0
  26. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/cache_output_tools.py +0 -0
  27. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/cache_output_tools_local.py +0 -0
  28. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/check_email_validity_tools.py +0 -0
  29. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/check_for_intent_signal.py +0 -0
  30. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
  31. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/clay_tools.py +0 -0
  32. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/clean_properties.py +0 -0
  33. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/company_utils.py +0 -0
  34. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/compose_salesnav_query.py +0 -0
  35. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/compose_search_query.py +0 -0
  36. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
  37. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/composite_tools.py +0 -0
  38. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/dataframe_tools.py +0 -0
  39. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/domain_parser.py +0 -0
  40. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/email_parse_helpers.py +0 -0
  41. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/email_provider.py +0 -0
  42. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/enrich_lead_information.py +0 -0
  43. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
  44. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/fetch_openai_config.py +0 -0
  45. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/field_validators.py +0 -0
  46. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/g2_tools.py +0 -0
  47. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_content.py +0 -0
  48. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_email.py +0 -0
  49. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_email_response.py +0 -0
  50. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_flow.py +0 -0
  51. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
  52. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
  53. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
  54. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
  55. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/google_custom_search.py +0 -0
  56. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/google_oauth_tools.py +0 -0
  57. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/google_workspace_tools.py +0 -0
  58. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/hubspot_clearbit.py +0 -0
  59. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
  60. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/instantly_tools.py +0 -0
  61. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/linkedin_crawler.py +0 -0
  62. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/lusha_tools.py +0 -0
  63. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/mailgun_tools.py +0 -0
  64. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/microsoft365_tools.py +0 -0
  65. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
  66. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openai_helpers.py +0 -0
  67. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  68. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
  69. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  70. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  71. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  72. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
  73. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/profile.py +0 -0
  74. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/proxy_curl_tools.py +0 -0
  75. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/proxycurl_search_leads.py +0 -0
  76. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/python_function_to_tools.py +0 -0
  77. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/research_lead.py +0 -0
  78. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
  79. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
  80. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/search_router.py +0 -0
  81. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/search_router_jobs.py +0 -0
  82. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/sendgrid_tools.py +0 -0
  83. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serarch_router_local_business.py +0 -0
  84. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
  85. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serpapi_google_jobs.py +0 -0
  86. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serpapi_google_search.py +0 -0
  87. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serpapi_local_business_search.py +0 -0
  88. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serpapi_search_tools.py +0 -0
  89. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serperdev_google_jobs.py +0 -0
  90. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serperdev_local_business.py +0 -0
  91. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/serperdev_search.py +0 -0
  92. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/smtp_email_tools.py +0 -0
  93. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/trasform_json.py +0 -0
  94. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/web_download_parse_tools.py +0 -0
  95. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/workflow_code_model.py +0 -0
  96. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/utils/zoominfo_tools.py +0 -0
  97. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/workflow/__init__.py +0 -0
  98. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/workflow/agent.py +0 -0
  99. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/workflow/flow.py +0 -0
  100. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/workflow/task.py +0 -0
  101. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana/workflow/test.py +0 -0
  102. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana.egg-info/SOURCES.txt +0 -0
  103. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana.egg-info/dependency_links.txt +0 -0
  104. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana.egg-info/entry_points.txt +0 -0
  105. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana.egg-info/requires.txt +0 -0
  106. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/src/dhisana.egg-info/top_level.txt +0 -0
  107. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_agent_tools.py +0 -0
  108. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_apollo_company_search.py +0 -0
  109. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_apollo_lead_search.py +0 -0
  110. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_google_document.py +0 -0
  111. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_hubspot_call_logs.py +0 -0
  112. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_linkedin_serper.py +0 -0
  113. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_mcp_connectivity.py +0 -0
  114. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_proxycurl_get_company_search_id.py +0 -0
  115. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/tests/test_proxycurl_job_count.py +0 -0
  116. {dhisana-0.0.1.dev222 → dhisana-0.0.1.dev224}/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.dev222
3
+ Version: 0.0.1.dev224
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-dev222',
5
+ version='0.0.1-dev224',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -1,5 +1,4 @@
1
1
  import asyncio
2
- import hashlib
3
2
  import json
4
3
  import logging
5
4
  import os
@@ -8,7 +7,6 @@ import aiohttp
8
7
  import backoff
9
8
 
10
9
  from dhisana.schemas.sales import LeadsQueryFilters, CompanyQueryFilters
11
- from dhisana.utils.cache_output_tools import cache_output, retrieve_output
12
10
  from dhisana.utils.assistant_tool_tag import assistant_tool
13
11
  from urllib.parse import urlparse, parse_qs
14
12
  from typing import Any, Dict, List, Optional, Tuple, Union
@@ -141,10 +139,6 @@ async def enrich_person_info_from_apollo(
141
139
  if linkedin_url:
142
140
  logger.debug(f"LinkedIn URL provided: {linkedin_url}")
143
141
  data['linkedin_url'] = linkedin_url
144
- cached_response = retrieve_output("enrich_person_info_from_apollo", linkedin_url)
145
- if cached_response is not None:
146
- logger.info(f"Cache hit for LinkedIn URL: {linkedin_url}")
147
- return cached_response
148
142
  if email:
149
143
  logger.debug(f"Email provided: {email}")
150
144
  data['email'] = email
@@ -165,8 +159,6 @@ async def enrich_person_info_from_apollo(
165
159
  logger.debug(f"Received response status: {response.status}")
166
160
  if response.status == 200:
167
161
  result = await response.json()
168
- if linkedin_url:
169
- cache_output("enrich_person_info_from_apollo", linkedin_url, result)
170
162
  logger.info("Successfully retrieved person info from Apollo.")
171
163
  return result
172
164
  elif response.status == 429:
@@ -232,16 +224,6 @@ async def lookup_person_in_apollo_by_name(
232
224
  "per_page": 10
233
225
  }
234
226
 
235
- # Build a cache key that includes full_name and company_name (if provided)
236
- # so that results are correctly cached and retrieved.
237
- key_item = f"lookup_person_in_apollo_by_name_{full_name}_{company_name or ''}".lower()
238
-
239
- # Attempt to retrieve a cached response first
240
- cached_response = retrieve_output("lookup_person_in_apollo_by_name", key_item)
241
- if cached_response is not None:
242
- logger.info(f"Cache hit for user: {full_name}, company: {company_name or ''}")
243
- return cached_response
244
-
245
227
  url = 'https://api.apollo.io/api/v1/mixed_people/search'
246
228
  logger.debug(f"Making request to Apollo with payload: {data}")
247
229
 
@@ -252,7 +234,6 @@ async def lookup_person_in_apollo_by_name(
252
234
  if response.status == 200:
253
235
  result = await response.json()
254
236
  logger.info("Successfully looked up person by name on Apollo.")
255
- cache_output("lookup_person_in_apollo_by_name", key_item, result)
256
237
  return result
257
238
  elif response.status == 429:
258
239
  msg = "Rate limit exceeded"
@@ -312,11 +293,6 @@ async def enrich_organization_info_from_apollo(
312
293
  else:
313
294
  headers["X-Api-Key"] = token
314
295
 
315
- cached_response = retrieve_output("enrich_organization_info_from_apollo", organization_domain)
316
- if cached_response is not None:
317
- logger.info(f"Cache hit for organization domain: {organization_domain}")
318
- return cached_response
319
-
320
296
  url = f'https://api.apollo.io/api/v1/organizations/enrich?domain={organization_domain}'
321
297
  logger.debug(f"Making GET request to Apollo for organization domain: {organization_domain}")
322
298
 
@@ -326,7 +302,6 @@ async def enrich_organization_info_from_apollo(
326
302
  logger.debug(f"Received response status: {response.status}")
327
303
  if response.status == 200:
328
304
  result = await response.json()
329
- cache_output("enrich_organization_info_from_apollo", organization_domain, result)
330
305
  logger.info("Successfully retrieved organization info from Apollo.")
331
306
  return result
332
307
  elif response.status == 429:
@@ -358,22 +333,12 @@ async def enrich_organization_info_from_apollo(
358
333
  )
359
334
  async def fetch_apollo_data(session, url: str, headers: Dict[str, str], payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
360
335
  logger.info("Entering fetch_apollo_data")
361
- key_data = f"{url}_{json.dumps(payload, sort_keys=True)}"
362
- key_hash = hashlib.sha256(key_data.encode()).hexdigest()
363
- logger.debug(f"Cache key hash: {key_hash}")
364
-
365
- cached_response = retrieve_output("fetch_apollo_data", key_hash)
366
- if cached_response is not None:
367
- logger.info("Cache hit for fetch_apollo_data.")
368
- return cached_response
369
-
370
- logger.debug("No cache hit. Making POST request to Apollo.")
336
+ logger.debug("Making POST request to Apollo.")
371
337
  async with session.post(url, headers=headers, json=payload) as response:
372
338
  logger.debug(f"Received response status: {response.status}")
373
339
  if response.status == 200:
374
340
  result = await response.json()
375
- cache_output("fetch_apollo_data", key_hash, result)
376
- logger.info("Successfully fetched data from Apollo and cached it.")
341
+ logger.info("Successfully fetched data from Apollo.")
377
342
  return result
378
343
  elif response.status == 429:
379
344
  msg = "Rate limit exceeded"
@@ -1019,11 +984,6 @@ async def get_organization_details_from_apollo(
1019
984
  else:
1020
985
  headers["X-Api-Key"] = token
1021
986
 
1022
- cached_response = retrieve_output("get_organization_details_from_apollo", organization_id)
1023
- if cached_response is not None:
1024
- logger.info(f"Cache hit for organization ID: {organization_id}")
1025
- return cached_response
1026
-
1027
987
  url = f'https://api.apollo.io/api/v1/organizations/{organization_id}'
1028
988
  logger.debug(f"Making GET request to Apollo for organization ID: {organization_id}")
1029
989
 
@@ -1035,7 +995,6 @@ async def get_organization_details_from_apollo(
1035
995
  result = await response.json()
1036
996
  org_details = result.get('organization', {})
1037
997
  if org_details:
1038
- cache_output("get_organization_details_from_apollo", organization_id, org_details)
1039
998
  logger.info("Successfully retrieved organization details from Apollo.")
1040
999
  return org_details
1041
1000
  else:
@@ -1055,6 +1055,109 @@ async def test_jinaai(api_key: str) -> Dict[str, Any]:
1055
1055
  return {"success": False, "status_code": 0, "error_message": str(exc)}
1056
1056
 
1057
1057
 
1058
+ async def test_firefliesai(api_key: str) -> Dict[str, Any]:
1059
+ """Validate Fireflies.ai API key by querying user metadata via GraphQL."""
1060
+ url = "https://api.fireflies.ai/graphql"
1061
+ headers = {
1062
+ "Authorization": f"Bearer {api_key}",
1063
+ "Content-Type": "application/json",
1064
+ }
1065
+
1066
+ # Try a couple of documented/observed query shapes — Fireflies occasionally
1067
+ # aliases the viewer field, so we fall back if the first choice is rejected.
1068
+ queries = [
1069
+ ("users", {"query": "{ users { name user_id } }"}, ("data", "users")),
1070
+ ("viewer", {"query": "query { viewer { id email } }"}, ("data", "viewer")),
1071
+ ("me", {"query": "query { me { id email } }"}, ("data", "me")),
1072
+ ("currentUser", {"query": "query { currentUser { id email } }"}, ("data", "currentUser")),
1073
+ ]
1074
+
1075
+ def extract_error(payload: Optional[Dict[str, Any]]) -> Optional[str]:
1076
+ if not isinstance(payload, dict):
1077
+ return None
1078
+ errors = payload.get("errors")
1079
+ if isinstance(errors, list):
1080
+ messages = [
1081
+ err.get("message") for err in errors
1082
+ if isinstance(err, dict) and err.get("message")
1083
+ ]
1084
+ if messages:
1085
+ return "; ".join(messages)
1086
+ elif errors:
1087
+ return str(errors)
1088
+ return (
1089
+ payload.get("message")
1090
+ or payload.get("error_description")
1091
+ or payload.get("error")
1092
+ )
1093
+
1094
+ try:
1095
+ timeout = aiohttp.ClientTimeout(total=10)
1096
+ async with aiohttp.ClientSession(timeout=timeout) as session:
1097
+ last_error: Optional[str] = None
1098
+
1099
+ for query_name, payload, data_path in queries:
1100
+ async with session.post(url, headers=headers, json=payload) as response:
1101
+ status = response.status
1102
+ data = await safe_json(response)
1103
+
1104
+ if status != 200:
1105
+ error_message = extract_error(data)
1106
+ if (
1107
+ error_message
1108
+ and "Cannot query field" in error_message
1109
+ and query_name != queries[-1][0]
1110
+ ):
1111
+ last_error = error_message
1112
+ continue
1113
+ return {
1114
+ "success": False,
1115
+ "status_code": status,
1116
+ "error_message": error_message or f"Non-200 from Fireflies.ai ({query_name})",
1117
+ }
1118
+
1119
+ if not isinstance(data, dict):
1120
+ return {
1121
+ "success": False,
1122
+ "status_code": status,
1123
+ "error_message": "Fireflies.ai returned non-JSON response.",
1124
+ }
1125
+
1126
+ error_message = extract_error(data)
1127
+ if error_message:
1128
+ last_error = error_message
1129
+ # If the error indicates the field is unknown, try the next query option.
1130
+ if "Cannot query field" in error_message and query_name != queries[-1][0]:
1131
+ continue
1132
+ return {
1133
+ "success": False,
1134
+ "status_code": status,
1135
+ "error_message": error_message,
1136
+ }
1137
+
1138
+ # Walk the data path to ensure the expected field exists.
1139
+ cursor: Any = data
1140
+ for key in data_path:
1141
+ if not isinstance(cursor, dict):
1142
+ cursor = None
1143
+ break
1144
+ cursor = cursor.get(key)
1145
+
1146
+ if cursor is not None:
1147
+ return {"success": True, "status_code": status, "error_message": None}
1148
+
1149
+ last_error = f"Fireflies.ai {query_name} response missing expected fields."
1150
+
1151
+ return {
1152
+ "success": False,
1153
+ "status_code": 200,
1154
+ "error_message": last_error or "Fireflies.ai queries did not return user data.",
1155
+ }
1156
+ except Exception as exc:
1157
+ logger.error(f"Fireflies.ai connectivity test failed: {exc}")
1158
+ return {"success": False, "status_code": 0, "error_message": str(exc)}
1159
+
1160
+
1058
1161
  async def test_firecrawl(api_key: str) -> Dict[str, Any]:
1059
1162
  """Quick check for Firecrawl API key validity."""
1060
1163
  url = "https://api.firecrawl.com/v1/scrape"
@@ -1250,6 +1353,7 @@ async def test_connectivity(tool_config: List[Dict[str, Any]]) -> Dict[str, Dict
1250
1353
  "findymail": test_findyemail,
1251
1354
  "datagma": test_datagma,
1252
1355
  "jinaai": test_jinaai,
1356
+ "firefliesai": test_firefliesai,
1253
1357
  "firecrawl": test_firecrawl,
1254
1358
  "youtube": test_youtube,
1255
1359
  "salesforce": test_salesforce,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev222
3
+ Version: 0.0.1.dev224
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
@@ -38,6 +38,22 @@ class TestConnectivity(unittest.TestCase):
38
38
  self.assertTrue(result['firecrawl']['success'])
39
39
  asyncio.run(runner())
40
40
 
41
+ def test_firefliesai_dispatch(self):
42
+ async def runner():
43
+ with patch('src.dhisana.utils.test_connect.test_firefliesai', new=AsyncMock(return_value={'success': True, 'status_code': 200, 'error_message': None})):
44
+ tool_config = [
45
+ {
46
+ 'name': 'firefliesai',
47
+ 'configuration': [
48
+ {'name': 'apiKey', 'value': 'dummy'}
49
+ ]
50
+ }
51
+ ]
52
+ result = await run_test_connectivity(tool_config)
53
+ self.assertIn('firefliesai', result)
54
+ self.assertTrue(result['firefliesai']['success'])
55
+ asyncio.run(runner())
56
+
41
57
  def test_salesforce_dispatch(self):
42
58
  async def runner():
43
59
  with patch(
File without changes
File without changes