dhisana 0.0.1.dev135__tar.gz → 0.0.1.dev136__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 (95) hide show
  1. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/PKG-INFO +1 -1
  2. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/setup.py +1 -1
  3. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/hubspot_crm_tools.py +184 -1
  4. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana.egg-info/PKG-INFO +1 -1
  5. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/README.md +0 -0
  6. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/pyproject.toml +0 -0
  7. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/setup.cfg +0 -0
  8. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/__init__.py +0 -0
  9. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/cli/__init__.py +0 -0
  10. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/cli/cli.py +0 -0
  11. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/cli/datasets.py +0 -0
  12. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/cli/models.py +0 -0
  13. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/cli/predictions.py +0 -0
  14. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/schemas/__init__.py +0 -0
  15. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/schemas/common.py +0 -0
  16. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/schemas/sales.py +0 -0
  17. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/ui/__init__.py +0 -0
  18. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/ui/components.py +0 -0
  19. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/__init__.py +0 -0
  20. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/add_mapping.py +0 -0
  21. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/agent_tools.py +0 -0
  22. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/apollo_tools.py +0 -0
  23. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/assistant_tool_tag.py +0 -0
  24. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/built_with_api_tools.py +0 -0
  25. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/cache_output_tools.py +0 -0
  26. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/cache_output_tools_local.py +0 -0
  27. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/check_email_validity_tools.py +0 -0
  28. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/check_for_intent_signal.py +0 -0
  29. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
  30. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/clay_tools.py +0 -0
  31. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/clean_properties.py +0 -0
  32. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/company_utils.py +0 -0
  33. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/compose_salesnav_query.py +0 -0
  34. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/compose_search_query.py +0 -0
  35. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
  36. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/composite_tools.py +0 -0
  37. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/dataframe_tools.py +0 -0
  38. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/domain_parser.py +0 -0
  39. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/email_parse_helpers.py +0 -0
  40. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/email_provider.py +0 -0
  41. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/enrich_lead_information.py +0 -0
  42. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
  43. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/fetch_openai_config.py +0 -0
  44. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/field_validators.py +0 -0
  45. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/g2_tools.py +0 -0
  46. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_content.py +0 -0
  47. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_email.py +0 -0
  48. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_email_response.py +0 -0
  49. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_flow.py +0 -0
  50. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_leads_salesnav.py +0 -0
  51. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
  52. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
  53. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/generate_structured_output_internal.py +0 -0
  54. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/google_custom_search.py +0 -0
  55. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/google_workspace_tools.py +0 -0
  56. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/hubspot_clearbit.py +0 -0
  57. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/instantly_tools.py +0 -0
  58. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/linkedin_crawler.py +0 -0
  59. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/lusha_tools.py +0 -0
  60. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
  61. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openai_helpers.py +0 -0
  62. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
  63. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
  64. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
  65. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
  66. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
  67. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
  68. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/proxy_curl_tools.py +0 -0
  69. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/python_function_to_tools.py +0 -0
  70. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/research_lead.py +0 -0
  71. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
  72. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
  73. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/search_router.py +0 -0
  74. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/sendgrid_tools.py +0 -0
  75. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
  76. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/serpapi_google_search.py +0 -0
  77. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/serpapi_search_tools.py +0 -0
  78. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/serperdev_search.py +0 -0
  79. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/smtp_email_tools.py +0 -0
  80. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/test_connect.py +0 -0
  81. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/trasform_json.py +0 -0
  82. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/web_download_parse_tools.py +0 -0
  83. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/workflow_code_model.py +0 -0
  84. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/utils/zoominfo_tools.py +0 -0
  85. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/workflow/__init__.py +0 -0
  86. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/workflow/agent.py +0 -0
  87. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/workflow/flow.py +0 -0
  88. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/workflow/task.py +0 -0
  89. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana/workflow/test.py +0 -0
  90. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana.egg-info/SOURCES.txt +0 -0
  91. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana.egg-info/dependency_links.txt +0 -0
  92. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana.egg-info/entry_points.txt +0 -0
  93. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana.egg-info/requires.txt +0 -0
  94. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/src/dhisana.egg-info/top_level.txt +0 -0
  95. {dhisana-0.0.1.dev135 → dhisana-0.0.1.dev136}/tests/test_agent_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev135
3
+ Version: 0.0.1.dev136
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-dev135',
5
+ version='0.0.1-dev136',
6
6
  description='A Python SDK for Dhisana AI Platform',
7
7
  author='Admin',
8
8
  author_email='contact@dhisana.ai',
@@ -19,7 +19,7 @@ from pydantic import BaseModel
19
19
  from dhisana.schemas.sales import HUBSPOT_TO_LEAD_MAPPING, HubSpotLeadInformation
20
20
  from dhisana.utils.assistant_tool_tag import assistant_tool
21
21
  from dhisana.utils.clean_properties import cleanup_properties
22
-
22
+ import logging
23
23
 
24
24
  # --------------------------------------------------------------------
25
25
  # 1. Retrieve HubSpot Access Token
@@ -2097,3 +2097,186 @@ async def create_hubspot_note_for_customer(
2097
2097
  if r.status != 201:
2098
2098
  raise RuntimeError(f"Create note failed {r.status}: {res}")
2099
2099
  return res
2100
+
2101
+
2102
+
2103
+ # ──────────────────────────────────────────────────────────────────────────────
2104
+ # Mapping between internal names ⇢ HubSpot company property names
2105
+ # ──────────────────────────────────────────────────────────────────────────────
2106
+ COMPANY_PROPERTY_MAPPING: Dict[str, str] = {
2107
+ "organization_name": "name",
2108
+ "primary_domain_of_organization": "domain",
2109
+ "organization_website": "website",
2110
+ }
2111
+
2112
+ # Only fill these if currently blank in HS
2113
+ CONDITIONAL_UPDATE_PROPS = {"domain", "website"}
2114
+
2115
+
2116
+ # ──────────────────────────────────────────────────────────────────────────────
2117
+ # Main upsert entry-point
2118
+ # ──────────────────────────────────────────────────────────────────────────────
2119
+ async def update_crm_company_record_function(
2120
+ company_values: Dict[str, Any],
2121
+ is_update: bool,
2122
+ hubspot_company_id: Optional[str] = None,
2123
+ organization_name: Optional[str] = None,
2124
+ domain: Optional[str] = None,
2125
+ organization_website: Optional[str] = None,
2126
+ tool_config: Optional[List[Dict]] = None,
2127
+ ) -> Dict[str, Any]:
2128
+ """
2129
+ Create **or** update a HubSpot *company*.
2130
+
2131
+ Parameters
2132
+ ----------
2133
+ company_values:
2134
+ Arbitrary key/value dict using **internal** names
2135
+ (``organization_name``, ``primary_domain_of_organization``, etc.)
2136
+ is_update:
2137
+ • ``True`` → do a best-effort lookup + patch if found
2138
+ • ``False`` → always create a fresh company
2139
+ hubspot_company_id:
2140
+ Pass a known HS ID to force an update to that record.
2141
+ """
2142
+ HUBSPOT_API_KEY = get_hubspot_access_token(tool_config)
2143
+ headers = {
2144
+ "Authorization": f"Bearer {HUBSPOT_API_KEY}",
2145
+ "Content-Type": "application/json",
2146
+ }
2147
+
2148
+ # ─── 1) Resolve allowed property names ───────────────────────────────────
2149
+ valid_props = await _fetch_all_company_properties(headers)
2150
+
2151
+ incoming_props: Dict[str, Any] = {}
2152
+ # a) from dict …
2153
+ for k, v in company_values.items():
2154
+ if v is None:
2155
+ continue
2156
+ mapped = COMPANY_PROPERTY_MAPPING.get(k)
2157
+ if mapped and mapped in valid_props:
2158
+ incoming_props[mapped] = v
2159
+
2160
+ # b) from explicit kwargs (fallbacks)
2161
+ if organization_name and "name" in valid_props:
2162
+ incoming_props.setdefault("name", organization_name)
2163
+ if domain and "domain" in valid_props:
2164
+ incoming_props.setdefault("domain", domain)
2165
+ if organization_website and "website" in valid_props:
2166
+ incoming_props.setdefault("website", organization_website)
2167
+
2168
+ # ─── 2) Upsert logic ─────────────────────────────────────────────────────
2169
+ found_company_id: Optional[str] = None
2170
+ if is_update:
2171
+ found_company_id = hubspot_company_id or await _find_existing_company(
2172
+ domain=domain,
2173
+ name=organization_name,
2174
+ valid_props=valid_props,
2175
+ tool_cfg=tool_config,
2176
+ )
2177
+
2178
+ if found_company_id:
2179
+ logging.info("↻ Updating existing company %s", found_company_id)
2180
+ return await _patch_company(
2181
+ company_id=found_company_id,
2182
+ incoming_props=incoming_props,
2183
+ headers=headers,
2184
+ )
2185
+
2186
+ logging.info("⊕ Creating new company with props: %s", incoming_props)
2187
+ return await _create_new_hubspot_company(incoming_props, headers)
2188
+
2189
+
2190
+ # ──────────────────────────────────────────────────────────────────────────────
2191
+ # Internal helpers
2192
+ # ──────────────────────────────────────────────────────────────────────────────
2193
+ async def _patch_company(
2194
+ company_id: str,
2195
+ incoming_props: Dict[str, Any],
2196
+ headers: Dict[str, str],
2197
+ ) -> Dict[str, Any]:
2198
+ """Patch only the changed / conditionally-empty properties."""
2199
+ current = await _get_company_by_id(company_id, headers)
2200
+ if not current:
2201
+ raise RuntimeError(f"Company {company_id} vanished during update step.")
2202
+
2203
+ current_props = current.get("properties", {})
2204
+ hubspot_props: Dict[str, Any] = {}
2205
+
2206
+ for prop, val in incoming_props.items():
2207
+ if prop in CONDITIONAL_UPDATE_PROPS:
2208
+ if _is_empty(current_props.get(prop)):
2209
+ hubspot_props[prop] = val
2210
+ else:
2211
+ hubspot_props[prop] = val
2212
+
2213
+ if not hubspot_props:
2214
+ logging.info("No new data to patch for company %s; skipping.", company_id)
2215
+ return current
2216
+
2217
+ url = f"https://api.hubapi.com/crm/v3/objects/companies/{company_id}"
2218
+ async with aiohttp.ClientSession() as s:
2219
+ async with s.patch(url, headers=headers, json={"properties": hubspot_props}) as r:
2220
+ res = await r.json()
2221
+ if r.status != 200:
2222
+ raise RuntimeError(f"Company update failed {r.status}: {res}")
2223
+ return res
2224
+
2225
+
2226
+ async def _create_new_hubspot_company(
2227
+ properties: Dict[str, Any], headers: Dict[str, str]
2228
+ ) -> Dict[str, Any]:
2229
+ url = "https://api.hubapi.com/crm/v3/objects/companies"
2230
+ async with aiohttp.ClientSession() as s:
2231
+ async with s.post(url, headers=headers, json={"properties": properties}) as r:
2232
+ data = await r.json()
2233
+ if r.status not in (200, 201):
2234
+ raise RuntimeError(f"Create company failed {r.status}: {data}")
2235
+ return data
2236
+
2237
+
2238
+ async def _find_existing_company(
2239
+ domain: Optional[str],
2240
+ name: Optional[str],
2241
+ valid_props: List[str],
2242
+ tool_cfg: Optional[List[Dict]],
2243
+ ) -> Optional[str]:
2244
+ """Return company ID if a matching record exists, else None."""
2245
+ filters = []
2246
+ if domain:
2247
+ filters.append({"propertyName": "domain", "operator": "EQ", "value": domain})
2248
+ if not filters and name:
2249
+ filters.append({"propertyName": "name", "operator": "EQ", "value": name})
2250
+
2251
+ if not filters:
2252
+ return None
2253
+
2254
+ res = await search_hubspot_objects(
2255
+ object_type="companies",
2256
+ filters=filters,
2257
+ limit=1,
2258
+ tool_config=tool_cfg,
2259
+ properties=["name", "domain", "website"],
2260
+ )
2261
+ hits = res.get("results", [])
2262
+ return hits[0]["id"] if hits else None
2263
+
2264
+
2265
+ async def _fetch_all_company_properties(headers: Dict[str, str]) -> List[str]:
2266
+ url = "https://api.hubapi.com/crm/v3/properties/companies"
2267
+ async with aiohttp.ClientSession() as s:
2268
+ async with s.get(url, headers=headers) as r:
2269
+ if r.status != 200:
2270
+ raise RuntimeError(f"Company prop fetch failed {r.status}: {await r.text()}")
2271
+ data = await r.json()
2272
+ return [p["name"] for p in data.get("results", [])]
2273
+
2274
+
2275
+ async def _get_company_by_id(company_id: str, headers: Dict[str, str]) -> Dict[str, Any]:
2276
+ url = f"https://api.hubapi.com/crm/v3/objects/companies/{company_id}"
2277
+ async with aiohttp.ClientSession() as s:
2278
+ async with s.get(url, headers=headers) as r:
2279
+ data = await r.json()
2280
+ if r.status != 200:
2281
+ raise RuntimeError(f"Fetch company {company_id} failed: {r.status} {data}")
2282
+ return data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dhisana
3
- Version: 0.0.1.dev135
3
+ Version: 0.0.1.dev136
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