dhisana 0.0.1.dev263__tar.gz → 0.0.1.dev264__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.dev263 → dhisana-0.0.1.dev264}/PKG-INFO +1 -1
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/setup.py +1 -1
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/enrich_lead_information.py +1 -1
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_email_response.py +44 -6
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_leads_salesnav.py +2 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_structured_output_internal.py +38 -13
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana.egg-info/PKG-INFO +1 -1
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/README.md +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/pyproject.toml +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/setup.cfg +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/cli/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/cli/cli.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/cli/datasets.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/cli/models.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/cli/predictions.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/schemas/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/schemas/common.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/schemas/sales.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/ui/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/ui/components.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/add_mapping.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/agent_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/apollo_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/assistant_tool_tag.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/built_with_api_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/cache_output_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/cache_output_tools_local.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/check_email_validity_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/check_for_intent_signal.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/check_linkedin_url_validity.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/clay_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/clean_properties.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/company_utils.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/compose_salesnav_query.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/compose_search_query.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/compose_three_step_workflow.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/composite_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/dataframe_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/domain_parser.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/email_body_utils.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/email_parse_helpers.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/email_provider.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/extract_email_content_for_llm.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/fetch_openai_config.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/field_validators.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/g2_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_content.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_custom_message.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_email.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_flow.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_linkedin_connect_message.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/generate_linkedin_response_message.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/google_custom_search.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/google_oauth_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/google_workspace_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/hubspot_clearbit.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/hubspot_crm_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/instantly_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/linkedin_crawler.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/lusha_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/mailgun_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/mailreach_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/microsoft365_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openai_assistant_and_file_utils.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openai_helpers.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openapi_spec_to_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openapi_tool/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openapi_tool/api_models.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openapi_tool/convert_openai_spec_to_tool.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openapi_tool/openapi_tool.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/parse_linkedin_messages_txt.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/profile.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/proxy_curl_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/proxycurl_search_leads.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/python_function_to_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/research_lead.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/sales_navigator_crawler.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/salesforce_crm_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/search_router.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/search_router_jobs.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/sendgrid_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serarch_router_local_business.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serpapi_additional_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serpapi_google_jobs.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serpapi_google_search.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serpapi_local_business_search.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serpapi_search_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serperdev_google_jobs.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serperdev_local_business.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/serperdev_search.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/smtp_email_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/test_connect.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/trasform_json.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/web_download_parse_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/workflow_code_model.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/zoominfo_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/workflow/__init__.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/workflow/agent.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/workflow/flow.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/workflow/task.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana/workflow/test.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana.egg-info/SOURCES.txt +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana.egg-info/dependency_links.txt +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana.egg-info/entry_points.txt +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana.egg-info/requires.txt +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/src/dhisana.egg-info/top_level.txt +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_agent_tools.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_apollo_company_search.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_apollo_lead_search.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_connectivity.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_email_body_utils.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_google_document.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_hubspot_call_logs.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_linkedin_serper.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_mailreach.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_mcp_connectivity.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_proxycurl_get_company_search_id.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_proxycurl_job_count.py +0 -0
- {dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/tests/test_structured_output_with_mcp.py +0 -0
|
@@ -16,6 +16,11 @@ from dhisana.utils.generate_structured_output_internal import (
|
|
|
16
16
|
get_structured_output_internal
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
# ---------------------------------------------------------------------------------------
|
|
20
|
+
# CONSTANTS
|
|
21
|
+
# ---------------------------------------------------------------------------------------
|
|
22
|
+
DEFAULT_TRIAGE_MODEL = "gpt-4.1"
|
|
23
|
+
|
|
19
24
|
# ---------------------------------------------------------------------------------------
|
|
20
25
|
# MODEL
|
|
21
26
|
# ---------------------------------------------------------------------------------------
|
|
@@ -194,7 +199,7 @@ async def get_inbound_email_triage_action(
|
|
|
194
199
|
triage_only, status = await get_structured_output_with_assistant_and_vector_store(
|
|
195
200
|
prompt=triage_prompt,
|
|
196
201
|
response_format=InboundEmailTriageResponse,
|
|
197
|
-
model=
|
|
202
|
+
model=DEFAULT_TRIAGE_MODEL,
|
|
198
203
|
vector_store_id=cleaned_context.external_known_data.external_openai_vector_store_id,
|
|
199
204
|
tool_config=tool_config,
|
|
200
205
|
use_cache=cleaned_context.message_instructions.use_cache if cleaned_context.message_instructions else True
|
|
@@ -203,13 +208,28 @@ async def get_inbound_email_triage_action(
|
|
|
203
208
|
triage_only, status = await get_structured_output_internal(
|
|
204
209
|
prompt=triage_prompt,
|
|
205
210
|
response_format=InboundEmailTriageResponse,
|
|
206
|
-
model=
|
|
211
|
+
model=DEFAULT_TRIAGE_MODEL,
|
|
207
212
|
tool_config=tool_config,
|
|
208
213
|
use_cache=cleaned_context.message_instructions.use_cache if cleaned_context.message_instructions else True
|
|
209
214
|
)
|
|
210
215
|
|
|
211
216
|
if status != "SUCCESS":
|
|
212
|
-
|
|
217
|
+
campaign_id = context.campaign_context.campaign_id if context.campaign_context else 'N/A'
|
|
218
|
+
if status == "CONTEXT_LENGTH_EXCEEDED":
|
|
219
|
+
raise Exception(
|
|
220
|
+
f"Email thread too long for model. Campaign ID: {campaign_id}. "
|
|
221
|
+
f"Consider truncating thread or switching models."
|
|
222
|
+
)
|
|
223
|
+
elif status in ("API_ERROR", "ERROR"):
|
|
224
|
+
raise Exception(
|
|
225
|
+
f"Error in generating triage action. Status: {status}. "
|
|
226
|
+
f"Campaign ID: {campaign_id}. Details: {triage_only}"
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
raise Exception(
|
|
230
|
+
f"Error in generating triage action. Status: {status}. "
|
|
231
|
+
f"Campaign ID: {campaign_id}"
|
|
232
|
+
)
|
|
213
233
|
return triage_only
|
|
214
234
|
|
|
215
235
|
|
|
@@ -393,7 +413,7 @@ async def generate_inbound_email_response_copy(
|
|
|
393
413
|
initial_response, status = await get_structured_output_with_assistant_and_vector_store(
|
|
394
414
|
prompt=prompt,
|
|
395
415
|
response_format=InboundEmailTriageResponse,
|
|
396
|
-
model=
|
|
416
|
+
model=DEFAULT_TRIAGE_MODEL,
|
|
397
417
|
vector_store_id=cleaned_context.external_known_data.external_openai_vector_store_id,
|
|
398
418
|
tool_config=tool_config
|
|
399
419
|
)
|
|
@@ -401,12 +421,30 @@ async def generate_inbound_email_response_copy(
|
|
|
401
421
|
initial_response, status = await get_structured_output_internal(
|
|
402
422
|
prompt=prompt,
|
|
403
423
|
response_format=InboundEmailTriageResponse,
|
|
404
|
-
model=
|
|
424
|
+
model=DEFAULT_TRIAGE_MODEL,
|
|
405
425
|
tool_config=tool_config
|
|
406
426
|
)
|
|
407
427
|
|
|
408
428
|
if status != "SUCCESS":
|
|
409
|
-
|
|
429
|
+
campaign_id = (
|
|
430
|
+
campaign_context.campaign_context.campaign_id
|
|
431
|
+
if campaign_context.campaign_context else 'N/A'
|
|
432
|
+
)
|
|
433
|
+
if status == "CONTEXT_LENGTH_EXCEEDED":
|
|
434
|
+
raise Exception(
|
|
435
|
+
f"Email thread too long for model. Campaign ID: {campaign_id}. "
|
|
436
|
+
f"Consider truncating thread or switching models."
|
|
437
|
+
)
|
|
438
|
+
elif status in ("API_ERROR", "ERROR"):
|
|
439
|
+
raise Exception(
|
|
440
|
+
f"Error in generating inbound email triage response. Status: {status}. "
|
|
441
|
+
f"Campaign ID: {campaign_id}. Details: {initial_response}"
|
|
442
|
+
)
|
|
443
|
+
else:
|
|
444
|
+
raise Exception(
|
|
445
|
+
f"Error in generating inbound email triage response. Status: {status}. "
|
|
446
|
+
f"Campaign ID: {campaign_id}"
|
|
447
|
+
)
|
|
410
448
|
|
|
411
449
|
response_item = MessageItem(
|
|
412
450
|
message_id="", # or generate one if appropriate
|
|
@@ -3,6 +3,7 @@ import hashlib
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
5
|
import random
|
|
6
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
6
7
|
|
|
7
8
|
from fastapi import HTTPException
|
|
8
9
|
from pydantic import BaseModel
|
|
@@ -17,11 +18,16 @@ from dhisana.utils.fetch_openai_config import (
|
|
|
17
18
|
_extract_config,
|
|
18
19
|
create_async_openai_client,
|
|
19
20
|
)
|
|
20
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
21
21
|
|
|
22
|
-
from openai import OpenAIError, RateLimitError
|
|
23
|
-
from pydantic import BaseModel
|
|
24
22
|
|
|
23
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
# 1. Helper functions
|
|
25
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
def is_context_length_error(error: Exception) -> bool:
|
|
28
|
+
"""Check if an error is due to context length being exceeded."""
|
|
29
|
+
error_str = str(error).lower()
|
|
30
|
+
return "context_length_exceeded" in error_str or "context window" in error_str
|
|
25
31
|
|
|
26
32
|
|
|
27
33
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -144,11 +150,17 @@ async def get_structured_output_internal(
|
|
|
144
150
|
completion = await _make_request()
|
|
145
151
|
break # success → exit loop
|
|
146
152
|
except (RateLimitError, OpenAIError) as e:
|
|
153
|
+
# Check for context length exceeded error
|
|
154
|
+
if is_context_length_error(e):
|
|
155
|
+
logging.error(f"Context length exceeded: {e}")
|
|
156
|
+
return f"Context length exceeded: {str(e)}", "CONTEXT_LENGTH_EXCEEDED"
|
|
157
|
+
|
|
147
158
|
# Detect 429 / rate-limit
|
|
159
|
+
error_str = str(e).lower()
|
|
148
160
|
is_rl = (
|
|
149
161
|
isinstance(e, RateLimitError)
|
|
150
162
|
or getattr(e, "status_code", None) == 429
|
|
151
|
-
or "rate_limit" in
|
|
163
|
+
or "rate_limit" in error_str
|
|
152
164
|
)
|
|
153
165
|
if is_rl and attempt < max_retries:
|
|
154
166
|
attempt += 1
|
|
@@ -161,7 +173,7 @@ async def get_structured_output_internal(
|
|
|
161
173
|
await asyncio.sleep(wait_time)
|
|
162
174
|
continue # retry once
|
|
163
175
|
logging.error(f"OpenAI API error: {e}")
|
|
164
|
-
|
|
176
|
+
return f"OpenAI API error: {str(e)}", "API_ERROR"
|
|
165
177
|
|
|
166
178
|
# ─── handle model output (unchanged) ────────────────────────────────
|
|
167
179
|
if completion and completion.output and len(completion.output) > 0:
|
|
@@ -203,12 +215,15 @@ async def get_structured_output_internal(
|
|
|
203
215
|
else:
|
|
204
216
|
return "No output returned", "FAIL"
|
|
205
217
|
|
|
218
|
+
# Safety fallback: catch any OpenAI errors not caught by inner retry loop
|
|
206
219
|
except OpenAIError as e:
|
|
207
220
|
logging.error(f"OpenAI API error: {e}")
|
|
208
|
-
|
|
221
|
+
if is_context_length_error(e):
|
|
222
|
+
return f"Context length exceeded: {str(e)}", "CONTEXT_LENGTH_EXCEEDED"
|
|
223
|
+
return f"OpenAI API error: {str(e)}", "API_ERROR"
|
|
209
224
|
except Exception as e:
|
|
210
225
|
logging.error(f"Unexpected error: {e}")
|
|
211
|
-
|
|
226
|
+
return f"Unexpected error: {str(e)}", "ERROR"
|
|
212
227
|
|
|
213
228
|
|
|
214
229
|
|
|
@@ -293,11 +308,17 @@ async def get_structured_output_with_mcp(
|
|
|
293
308
|
return await client_async.responses.create(**kwargs)
|
|
294
309
|
|
|
295
310
|
# ─── Retry once for 429s ──────────────────────────────────────────────────
|
|
311
|
+
completion = None
|
|
296
312
|
for attempt in range(2):
|
|
297
313
|
try:
|
|
298
314
|
completion = await _make_request()
|
|
299
315
|
break
|
|
300
316
|
except (RateLimitError, OpenAIError) as exc:
|
|
317
|
+
# Check for context length exceeded error
|
|
318
|
+
if is_context_length_error(exc):
|
|
319
|
+
logging.error(f"Context length exceeded: {exc}")
|
|
320
|
+
return f"Context length exceeded: {str(exc)}", "CONTEXT_LENGTH_EXCEEDED"
|
|
321
|
+
|
|
301
322
|
if attempt == 0 and (
|
|
302
323
|
isinstance(exc, RateLimitError)
|
|
303
324
|
or getattr(exc, "status_code", None) == 429
|
|
@@ -308,9 +329,10 @@ async def get_structured_output_with_mcp(
|
|
|
308
329
|
await asyncio.sleep(sleep_for)
|
|
309
330
|
continue
|
|
310
331
|
logging.error("OpenAI API error: %s", exc)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
332
|
+
return f"OpenAI API error: {str(exc)}", "API_ERROR"
|
|
333
|
+
|
|
334
|
+
if not completion:
|
|
335
|
+
return "OpenAI request retry loop failed", "API_ERROR"
|
|
314
336
|
|
|
315
337
|
# ─── Parse the model’s structured output ──────────────────────────────────
|
|
316
338
|
if not (completion and completion.output):
|
|
@@ -438,7 +460,7 @@ async def get_structured_output_with_assistant_and_vector_store(
|
|
|
438
460
|
break
|
|
439
461
|
|
|
440
462
|
if not raw_text or not raw_text.strip():
|
|
441
|
-
|
|
463
|
+
return "No response from the model", "FAIL"
|
|
442
464
|
|
|
443
465
|
try:
|
|
444
466
|
parsed_obj = response_format.parse_raw(raw_text)
|
|
@@ -454,9 +476,12 @@ async def get_structured_output_with_assistant_and_vector_store(
|
|
|
454
476
|
else:
|
|
455
477
|
return "No output returned", "FAIL"
|
|
456
478
|
|
|
479
|
+
# Safety fallback: catch any errors not caught during API call
|
|
457
480
|
except OpenAIError as e:
|
|
458
481
|
logging.error(f"OpenAI API error: {e}")
|
|
459
|
-
|
|
482
|
+
if is_context_length_error(e):
|
|
483
|
+
return f"Context length exceeded: {str(e)}", "CONTEXT_LENGTH_EXCEEDED"
|
|
484
|
+
return f"OpenAI API error: {str(e)}", "API_ERROR"
|
|
460
485
|
except Exception as e:
|
|
461
486
|
logging.error(f"Unexpected error: {e}")
|
|
462
|
-
|
|
487
|
+
return f"Unexpected error: {str(e)}", "ERROR"
|
|
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.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/check_email_validity_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
{dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/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.dev263 → dhisana-0.0.1.dev264}/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
|
{dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/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
|
{dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/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.dev263 → dhisana-0.0.1.dev264}/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.dev263 → dhisana-0.0.1.dev264}/src/dhisana/utils/openapi_tool/openapi_tool.py
RENAMED
|
File without changes
|
{dhisana-0.0.1.dev263 → dhisana-0.0.1.dev264}/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.dev263 → dhisana-0.0.1.dev264}/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.dev263 → dhisana-0.0.1.dev264}/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
|
|
File without changes
|
|
File without changes
|