From 3ea235a66655489b4e226ca4496c8eb0823207e7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 5 Mar 2026 13:43:13 +0530 Subject: [PATCH] fix: fix circuit breaker failure recording fix: fix circuit breaker failure recording chore: provide advanced configuration option in UI for campaigns --- api/db/campaign_client.py | 18 ++++ api/routes/campaign.py | 39 +++++++- api/routes/organization.py | 76 +++++++++++++++- api/routes/telephony.py | 4 +- .../campaign/campaign_call_dispatcher.py | 4 + api/services/telephony/ari_manager.py | 3 +- .../providers/ari_call_strategies.py | 8 +- .../telephony/providers/ari_provider.py | 4 +- .../telephony/providers/cloudonix_provider.py | 7 +- .../providers/twilio_call_strategies.py | 16 +++- api/tasks/knowledge_base_processing.py | 10 ++ .../campaigns/CampaignAdvancedSettings.tsx | 75 +++++++++++++++ .../app/campaigns/[campaignId]/edit/page.tsx | 43 +++++++-- ui/src/app/campaigns/new/page.tsx | 91 ++++++++++++++++--- ui/src/app/files/DocumentUpload.tsx | 14 ++- ui/src/client/sdk.gen.ts | 22 ++++- ui/src/client/types.gen.ts | 72 +++++++++++++-- 17 files changed, 448 insertions(+), 58 deletions(-) diff --git a/api/db/campaign_client.py b/api/db/campaign_client.py index 6a873cd..9595880 100644 --- a/api/db/campaign_client.py +++ b/api/db/campaign_client.py @@ -22,6 +22,7 @@ class CampaignClient(BaseDBClient): retry_config: Optional[dict] = None, max_concurrency: Optional[int] = None, schedule_config: Optional[dict] = None, + circuit_breaker: Optional[dict] = None, ) -> CampaignModel: """Create a new campaign""" async with self.async_session() as session: @@ -31,6 +32,8 @@ class CampaignClient(BaseDBClient): orchestrator_metadata["max_concurrency"] = max_concurrency if schedule_config is not None: orchestrator_metadata["schedule_config"] = schedule_config + if circuit_breaker is not None: + orchestrator_metadata["circuit_breaker"] = circuit_breaker campaign = CampaignModel( name=name, @@ -68,6 +71,21 @@ class CampaignClient(BaseDBClient): result = await session.execute(query) return list(result.scalars().all()) + async def get_latest_campaign( + self, + organization_id: int, + ) -> Optional[CampaignModel]: + """Get the most recently created campaign for an organization""" + async with self.async_session() as session: + query = ( + select(CampaignModel) + .where(CampaignModel.organization_id == organization_id) + .order_by(CampaignModel.created_at.desc()) + .limit(1) + ) + result = await session.execute(query) + return result.scalars().first() + async def get_campaign( self, campaign_id: int, diff --git a/api/routes/campaign.py b/api/routes/campaign.py index 5c978b5..6a3b58c 100644 --- a/api/routes/campaign.py +++ b/api/routes/campaign.py @@ -6,7 +6,10 @@ from zoneinfo import ZoneInfo from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel, Field, field_validator, model_validator -from api.constants import DEFAULT_CAMPAIGN_RETRY_CONFIG, DEFAULT_ORG_CONCURRENCY_LIMIT +from api.constants import ( + DEFAULT_CAMPAIGN_RETRY_CONFIG, + DEFAULT_ORG_CONCURRENCY_LIMIT, +) from api.db import db_client from api.db.models import UserModel from api.enums import OrganizationConfigurationKey @@ -126,6 +129,20 @@ class ScheduleConfigResponse(BaseModel): slots: List[TimeSlotResponse] +class CircuitBreakerConfigRequest(BaseModel): + enabled: bool = True + failure_threshold: float = Field(default=0.5, ge=0.0, le=1.0) + window_seconds: int = Field(default=120, ge=30, le=600) + min_calls_in_window: int = Field(default=5, ge=1, le=100) + + +class CircuitBreakerConfigResponse(BaseModel): + enabled: bool + failure_threshold: float + window_seconds: int + min_calls_in_window: int + + class CreateCampaignRequest(BaseModel): name: str = Field(..., min_length=1, max_length=255) workflow_id: int @@ -134,6 +151,7 @@ class CreateCampaignRequest(BaseModel): retry_config: Optional[RetryConfigRequest] = None max_concurrency: Optional[int] = Field(default=None, ge=1, le=100) schedule_config: Optional[ScheduleConfigRequest] = None + circuit_breaker: Optional[CircuitBreakerConfigRequest] = None class UpdateCampaignRequest(BaseModel): @@ -141,6 +159,7 @@ class UpdateCampaignRequest(BaseModel): retry_config: Optional[RetryConfigRequest] = None max_concurrency: Optional[int] = Field(default=None, ge=1, le=100) schedule_config: Optional[ScheduleConfigRequest] = None + circuit_breaker: Optional[CircuitBreakerConfigRequest] = None class CampaignResponse(BaseModel): @@ -160,6 +179,7 @@ class CampaignResponse(BaseModel): retry_config: RetryConfigResponse max_concurrency: Optional[int] = None schedule_config: Optional[ScheduleConfigResponse] = None + circuit_breaker: Optional[CircuitBreakerConfigResponse] = None class CampaignsResponse(BaseModel): @@ -209,9 +229,10 @@ def _build_campaign_response(campaign, workflow_name: str) -> CampaignResponse: else DEFAULT_CAMPAIGN_RETRY_CONFIG ) - # Get max_concurrency and schedule_config from orchestrator_metadata + # Get max_concurrency, schedule_config, circuit_breaker from orchestrator_metadata max_concurrency = None schedule_config = None + circuit_breaker_config = None if campaign.orchestrator_metadata: max_concurrency = campaign.orchestrator_metadata.get("max_concurrency") sc = campaign.orchestrator_metadata.get("schedule_config") @@ -221,6 +242,9 @@ def _build_campaign_response(campaign, workflow_name: str) -> CampaignResponse: timezone=sc.get("timezone", "UTC"), slots=[TimeSlotResponse(**slot) for slot in sc.get("slots", [])], ) + cb = campaign.orchestrator_metadata.get("circuit_breaker") + if cb: + circuit_breaker_config = CircuitBreakerConfigResponse(**cb) return CampaignResponse( id=campaign.id, @@ -239,6 +263,7 @@ def _build_campaign_response(campaign, workflow_name: str) -> CampaignResponse: retry_config=RetryConfigResponse(**retry_config), max_concurrency=max_concurrency, schedule_config=schedule_config, + circuit_breaker=circuit_breaker_config, ) @@ -276,6 +301,11 @@ async def create_campaign( if request.schedule_config: schedule_config = request.schedule_config.model_dump() + # Build circuit_breaker dict if provided + circuit_breaker_config = None + if request.circuit_breaker: + circuit_breaker_config = request.circuit_breaker.model_dump() + campaign = await db_client.create_campaign( name=request.name, workflow_id=request.workflow_id, @@ -286,6 +316,7 @@ async def create_campaign( retry_config=retry_config, max_concurrency=request.max_concurrency, schedule_config=schedule_config, + circuit_breaker=circuit_breaker_config, ) return _build_campaign_response(campaign, workflow_name) @@ -436,6 +467,10 @@ async def update_campaign( metadata["schedule_config"] = request.schedule_config.model_dump() metadata_changed = True + if request.circuit_breaker is not None: + metadata["circuit_breaker"] = request.circuit_breaker.model_dump() + metadata_changed = True + if metadata_changed: update_kwargs["orchestrator_metadata"] = metadata diff --git a/api/routes/organization.py b/api/routes/organization.py index f840df8..c2085ab 100644 --- a/api/routes/organization.py +++ b/api/routes/organization.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import List, Optional, Union from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel @@ -257,14 +257,41 @@ class RetryConfigResponse(BaseModel): retry_on_voicemail: bool -class CampaignLimitsResponse(BaseModel): +class TimeSlotResponse(BaseModel): + day_of_week: int + start_time: str + end_time: str + + +class ScheduleConfigResponse(BaseModel): + enabled: bool + timezone: str + slots: List[TimeSlotResponse] + + +class CircuitBreakerConfigResponse(BaseModel): + enabled: bool + failure_threshold: float + window_seconds: int + min_calls_in_window: int + + +class LastCampaignSettingsResponse(BaseModel): + retry_config: Optional[RetryConfigResponse] = None + max_concurrency: Optional[int] = None + schedule_config: Optional[ScheduleConfigResponse] = None + circuit_breaker: Optional[CircuitBreakerConfigResponse] = None + + +class CampaignDefaultsResponse(BaseModel): concurrent_call_limit: int from_numbers_count: int default_retry_config: RetryConfigResponse + last_campaign_settings: Optional[LastCampaignSettingsResponse] = None -@router.get("/campaign-limits", response_model=CampaignLimitsResponse) -async def get_campaign_limits(user: UserModel = Depends(get_user)): +@router.get("/campaign-defaults", response_model=CampaignDefaultsResponse) +async def get_campaign_defaults(user: UserModel = Depends(get_user)): """Get campaign limits for the user's organization. Returns the organization's concurrent call limit and default retry configuration. @@ -299,8 +326,47 @@ async def get_campaign_limits(user: UserModel = Depends(get_user)): except Exception: pass - return CampaignLimitsResponse( + # Get last campaign settings for pre-population + last_campaign_settings = None + try: + last_campaign = await db_client.get_latest_campaign( + user.selected_organization_id + ) + if last_campaign: + retry = None + if last_campaign.retry_config: + retry = RetryConfigResponse(**last_campaign.retry_config) + + max_conc = None + sched = None + cb = None + if last_campaign.orchestrator_metadata: + max_conc = last_campaign.orchestrator_metadata.get("max_concurrency") + sc = last_campaign.orchestrator_metadata.get("schedule_config") + if sc: + sched = ScheduleConfigResponse( + enabled=sc.get("enabled", False), + timezone=sc.get("timezone", "UTC"), + slots=[ + TimeSlotResponse(**slot) for slot in sc.get("slots", []) + ], + ) + cb_data = last_campaign.orchestrator_metadata.get("circuit_breaker") + if cb_data: + cb = CircuitBreakerConfigResponse(**cb_data) + + last_campaign_settings = LastCampaignSettingsResponse( + retry_config=retry, + max_concurrency=max_conc, + schedule_config=sched, + circuit_breaker=cb, + ) + except Exception: + pass + + return CampaignDefaultsResponse( concurrent_call_limit=concurrent_limit, from_numbers_count=from_numbers_count, default_retry_config=RetryConfigResponse(**DEFAULT_CAMPAIGN_RETRY_CONFIG), + last_campaign_settings=last_campaign_settings, ) diff --git a/api/routes/telephony.py b/api/routes/telephony.py index e5bc771..5537c55 100644 --- a/api/routes/telephony.py +++ b/api/routes/telephony.py @@ -783,7 +783,8 @@ async def _process_status_update(workflow_run_id: int, status: StatusCallbackReq if workflow_run.campaign_id: await campaign_call_dispatcher.release_call_slot(workflow_run_id) await circuit_breaker.record_and_evaluate( - workflow_run.campaign_id, is_failure=True + workflow_run.campaign_id, + is_failure=status.status == "error", ) # Check if retry is needed for campaign calls (busy/no-answer) @@ -1209,6 +1210,7 @@ async def handle_cloudonix_status_callback( return {"status": "success"} + @router.post("/cloudonix/amd-callback/{workflow_run_id}") async def handle_cloudonix_amd_callback( workflow_run_id: int, diff --git a/api/services/campaign/campaign_call_dispatcher.py b/api/services/campaign/campaign_call_dispatcher.py index 121ef39..ce393a7 100644 --- a/api/services/campaign/campaign_call_dispatcher.py +++ b/api/services/campaign/campaign_call_dispatcher.py @@ -9,6 +9,7 @@ from api.constants import DEFAULT_ORG_CONCURRENCY_LIMIT from api.db import db_client from api.db.models import QueuedRunModel, WorkflowRunModel from api.enums import OrganizationConfigurationKey, WorkflowRunState +from api.services.campaign.circuit_breaker import circuit_breaker from api.services.campaign.errors import ( ConcurrentSlotAcquisitionError, PhoneNumberPoolExhaustedError, @@ -315,6 +316,9 @@ class CampaignCallDispatcher: }, ) + # Record call initiation failure in circuit breaker + await circuit_breaker.record_and_evaluate(campaign.id, is_failure=True) + # Release concurrent slot on failure mapping = await rate_limiter.get_workflow_slot_mapping(workflow_run.id) if mapping: diff --git a/api/services/telephony/ari_manager.py b/api/services/telephony/ari_manager.py index 98dacfc..eebfde7 100644 --- a/api/services/telephony/ari_manager.py +++ b/api/services/telephony/ari_manager.py @@ -14,7 +14,6 @@ setup_logging() import asyncio import json import signal -import time from typing import Dict, Optional, Set from urllib.parse import urlparse @@ -628,7 +627,7 @@ class ARIConnection: bridge_id = ctx.get("bridge_id") transfer_state = ctx.get("transfer_state") - # Check if this is a call transfer scenario external channel. Skip full teardown if + # Check if this is a call transfer scenario external channel. Skip full teardown if # transfer is in progress and this is the external media channel # During call transfer, we preserve the caller-destination bridge if ( diff --git a/api/services/telephony/providers/ari_call_strategies.py b/api/services/telephony/providers/ari_call_strategies.py index 5225a29..4e02c8e 100644 --- a/api/services/telephony/providers/ari_call_strategies.py +++ b/api/services/telephony/providers/ari_call_strategies.py @@ -45,13 +45,16 @@ class ARIBridgeSwapStrategy(TransferStrategy): from api.services.telephony.call_transfer_manager import ( get_call_transfer_manager, ) + auth = BasicAuth(app_name, app_password) # Get call transfer manager instance call_transfer_manager = await get_call_transfer_manager() # 1. Find active transfer context for this caller channel - transfer_context = await call_transfer_manager.find_transfer_context_for_call(channel_id) + transfer_context = ( + await call_transfer_manager.find_transfer_context_for_call(channel_id) + ) if not transfer_context: logger.error( f"[ARI Transfer] No active transfer context found for caller {channel_id}" @@ -178,6 +181,7 @@ class ARIBridgeSwapStrategy(TransferStrategy): logger.exception(f"Failed to execute ARI transfer: {e}") return False + class ARIHangupStrategy(HangupStrategy): """Implements hangup for Asterisk ARI channels.""" @@ -223,4 +227,4 @@ class ARIHangupStrategy(HangupStrategy): except Exception as e: logger.exception(f"Failed to hang up Asterisk channel: {e}") - return False \ No newline at end of file + return False diff --git a/api/services/telephony/providers/ari_provider.py b/api/services/telephony/providers/ari_provider.py index 7d7fce1..4e2071c 100644 --- a/api/services/telephony/providers/ari_provider.py +++ b/api/services/telephony/providers/ari_provider.py @@ -455,7 +455,9 @@ class ARIProvider(TelephonyProvider): } except Exception as e: - logger.error(f"[ARI Transfer] Failed to originate call transfer destination channel: {e}") + logger.error( + f"[ARI Transfer] Failed to originate call transfer destination channel: {e}" + ) await call_transfer_manager.remove_transfer_context(transfer_id) raise diff --git a/api/services/telephony/providers/cloudonix_provider.py b/api/services/telephony/providers/cloudonix_provider.py index 123c813..8bbc668 100644 --- a/api/services/telephony/providers/cloudonix_provider.py +++ b/api/services/telephony/providers/cloudonix_provider.py @@ -107,9 +107,10 @@ class CloudonixProvider(TelephonyProvider): } data["machineDetection"] = "DetectMessageEnd" data["asyncAmd"] = True - data["asyncAmdStatusCallback"] = f"{backend_endpoint}/api/v1/telephony/cloudonix/amd-callback/{workflow_run_id}" - data["asyncAmdStatusCallbackMethod"]= "POST" - + data["asyncAmdStatusCallback"] = ( + f"{backend_endpoint}/api/v1/telephony/cloudonix/amd-callback/{workflow_run_id}" + ) + data["asyncAmdStatusCallbackMethod"] = "POST" # TODO: Cloudonix status callbacks are spammy, so commenting it out. Can send it to # some persistent logging system instead of transcational database. diff --git a/api/services/telephony/providers/twilio_call_strategies.py b/api/services/telephony/providers/twilio_call_strategies.py index d48cff3..003eb33 100644 --- a/api/services/telephony/providers/twilio_call_strategies.py +++ b/api/services/telephony/providers/twilio_call_strategies.py @@ -76,20 +76,26 @@ class TwilioConferenceStrategy(TransferStrategy): ) # 3. Clean up transfer context after successful transfer - await self._cleanup_transfer_context(transfer_context.transfer_id) + await self._cleanup_transfer_context( + transfer_context.transfer_id + ) return True elif response.status == 404: logger.error( f"Failed to transfer Twilio call {call_sid}: Call not found (404)" ) - await self._cleanup_transfer_context(transfer_context.transfer_id) + await self._cleanup_transfer_context( + transfer_context.transfer_id + ) return False else: logger.error( f"Failed to transfer Twilio call {call_sid} to conference {conference_name}: " f"Status {response.status}, Response: {response_text}" ) - await self._cleanup_transfer_context(transfer_context.transfer_id) + await self._cleanup_transfer_context( + transfer_context.transfer_id + ) return False except Exception as e: @@ -132,7 +138,7 @@ class TwilioConferenceStrategy(TransferStrategy): from api.services.telephony.call_transfer_manager import ( get_call_transfer_manager, ) - + call_transfer_manager = await get_call_transfer_manager() await call_transfer_manager.remove_transfer_context(transfer_id) except Exception as e: @@ -183,4 +189,4 @@ class TwilioHangupStrategy(HangupStrategy): except Exception as e: logger.exception(f"Failed to hang up Twilio call: {e}") - return False \ No newline at end of file + return False diff --git a/api/tasks/knowledge_base_processing.py b/api/tasks/knowledge_base_processing.py index fe0d996..e4fbaaf 100644 --- a/api/tasks/knowledge_base_processing.py +++ b/api/tasks/knowledge_base_processing.py @@ -69,6 +69,16 @@ async def process_knowledge_base_document( file_size = os.path.getsize(temp_file_path) logger.info(f"Downloaded file size: {file_size} bytes") + # Validate file size (max 5MB) + max_file_size = 5 * 1024 * 1024 + if file_size > max_file_size: + error_message = f"File size ({file_size / (1024 * 1024):.1f}MB) exceeds the maximum allowed size of 5MB." + logger.warning(f"Document {document_id}: {error_message}") + await db_client.update_document_status( + document_id, "failed", error_message=error_message + ) + return + # Compute file hash and get mime type file_hash = db_client.compute_file_hash(temp_file_path) mime_type = db_client.get_mime_type(temp_file_path) diff --git a/ui/src/app/campaigns/CampaignAdvancedSettings.tsx b/ui/src/app/campaigns/CampaignAdvancedSettings.tsx index 63a76ef..7a49499 100644 --- a/ui/src/app/campaigns/CampaignAdvancedSettings.tsx +++ b/ui/src/app/campaigns/CampaignAdvancedSettings.tsx @@ -46,6 +46,15 @@ export interface CampaignAdvancedSettingsProps { onScheduleTimezoneChange: (value: ITimezoneOption | string) => void; timeSlots: TimeSlot[]; onTimeSlotsChange: (value: TimeSlot[]) => void; + // Circuit breaker config + circuitBreakerEnabled: boolean; + onCircuitBreakerEnabledChange: (value: boolean) => void; + circuitBreakerFailureThreshold: string; + onCircuitBreakerFailureThresholdChange: (value: string) => void; + circuitBreakerWindowSeconds: string; + onCircuitBreakerWindowSecondsChange: (value: string) => void; + circuitBreakerMinCalls: string; + onCircuitBreakerMinCallsChange: (value: string) => void; } /** Extract the string timezone value from ITimezoneOption | string */ @@ -101,6 +110,10 @@ export default function CampaignAdvancedSettings({ retryOnVoicemail, onRetryOnVoicemailChange, scheduleEnabled, onScheduleEnabledChange, scheduleTimezone, onScheduleTimezoneChange, timeSlots, onTimeSlotsChange, + circuitBreakerEnabled, onCircuitBreakerEnabledChange, + circuitBreakerFailureThreshold, onCircuitBreakerFailureThresholdChange, + circuitBreakerWindowSeconds, onCircuitBreakerWindowSecondsChange, + circuitBreakerMinCalls, onCircuitBreakerMinCallsChange, }: CampaignAdvancedSettingsProps) { const timezoneSelectId = useId(); @@ -295,6 +308,68 @@ export default function CampaignAdvancedSettings({ )} + + + + {/* Circuit Breaker */} +
+
+
+ +

+ Auto-pause campaign on high failure rates +

+
+ +
+ + {circuitBreakerEnabled && ( +
+
+ + onCircuitBreakerFailureThresholdChange(e.target.value)} + min={1} + max={100} + /> +

+ Pause when failure rate exceeds this percentage +

+
+
+
+ + onCircuitBreakerWindowSecondsChange(e.target.value)} + min={30} + max={600} + /> +
+
+ + onCircuitBreakerMinCallsChange(e.target.value)} + min={1} + max={100} + /> +
+
+
+ )} +
); } diff --git a/ui/src/app/campaigns/[campaignId]/edit/page.tsx b/ui/src/app/campaigns/[campaignId]/edit/page.tsx index 02eb5d5..cf2629c 100644 --- a/ui/src/app/campaigns/[campaignId]/edit/page.tsx +++ b/ui/src/app/campaigns/[campaignId]/edit/page.tsx @@ -8,8 +8,8 @@ import { toast } from 'sonner'; import { getCampaignApiV1CampaignCampaignIdGet, - getCampaignLimitsApiV1OrganizationsCampaignLimitsGet, - updateCampaignApiV1CampaignCampaignIdPatch, + getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet, + updateCampaignApiV1CampaignCampaignIdPatch } from '@/client/sdk.gen'; import type { CampaignResponse } from '@/client/types.gen'; import { Button } from '@/components/ui/button'; @@ -55,6 +55,11 @@ export default function EditCampaignPage() { const [timeSlots, setTimeSlots] = useState([ { day_of_week: 0, start_time: '09:00', end_time: '17:00' }, ]); + // Circuit breaker config state + const [circuitBreakerEnabled, setCircuitBreakerEnabled] = useState(true); + const [circuitBreakerFailureThreshold, setCircuitBreakerFailureThreshold] = useState('50'); + const [circuitBreakerWindowSeconds, setCircuitBreakerWindowSeconds] = useState('120'); + const [circuitBreakerMinCalls, setCircuitBreakerMinCalls] = useState('5'); // Redirect if not authenticated useEffect(() => { @@ -104,6 +109,15 @@ export default function EditCampaignPage() { setTimeSlots(c.schedule_config.slots.map(s => ({ ...s }))); } } + + // Circuit breaker config + const cb = (c as unknown as { circuit_breaker?: { enabled: boolean; failure_threshold: number; window_seconds: number; min_calls_in_window: number } }).circuit_breaker; + if (cb) { + setCircuitBreakerEnabled(cb.enabled); + setCircuitBreakerFailureThreshold(String(Math.round(cb.failure_threshold * 100))); + setCircuitBreakerWindowSeconds(String(cb.window_seconds)); + setCircuitBreakerMinCalls(String(cb.min_calls_in_window)); + } } } catch (error) { console.error('Failed to fetch campaign:', error); @@ -115,11 +129,11 @@ export default function EditCampaignPage() { }, [user, getAccessToken, campaignId, router]); // Fetch campaign limits - const fetchCampaignLimits = useCallback(async () => { + const fetchCampaignDefaults = useCallback(async () => { if (!user) return; try { const accessToken = await getAccessToken(); - const response = await getCampaignLimitsApiV1OrganizationsCampaignLimitsGet({ + const response = await getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet({ headers: { 'Authorization': `Bearer ${accessToken}` }, }); @@ -136,9 +150,9 @@ export default function EditCampaignPage() { useEffect(() => { if (user) { fetchCampaign(); - fetchCampaignLimits(); + fetchCampaignDefaults(); } - }, [fetchCampaign, fetchCampaignLimits, user]); + }, [fetchCampaign, fetchCampaignDefaults, user]); // Effective concurrency limit const effectiveLimit = fromNumbersCount > 0 @@ -213,6 +227,14 @@ export default function EditCampaignPage() { slots: [{ day_of_week: 0, start_time: '09:00', end_time: '17:00' }], }; + const circuitBreakerConfig = { + enabled: circuitBreakerEnabled, + failure_threshold: (parseInt(circuitBreakerFailureThreshold) || 50) / 100, + window_seconds: parseInt(circuitBreakerWindowSeconds) || 120, + min_calls_in_window: parseInt(circuitBreakerMinCalls) || 5, + }; + + const response = await updateCampaignApiV1CampaignCampaignIdPatch({ path: { campaign_id: campaignId }, body: { @@ -220,6 +242,7 @@ export default function EditCampaignPage() { retry_config: retryConfig, max_concurrency: maxConcurrencyValue, schedule_config: scheduleConfig, + circuit_breaker: circuitBreakerConfig, }, headers: { 'Authorization': `Bearer ${accessToken}` }, }); @@ -332,6 +355,14 @@ export default function EditCampaignPage() { onScheduleTimezoneChange={setScheduleTimezone} timeSlots={timeSlots} onTimeSlotsChange={setTimeSlots} + circuitBreakerEnabled={circuitBreakerEnabled} + onCircuitBreakerEnabledChange={setCircuitBreakerEnabled} + circuitBreakerFailureThreshold={circuitBreakerFailureThreshold} + onCircuitBreakerFailureThresholdChange={setCircuitBreakerFailureThreshold} + circuitBreakerWindowSeconds={circuitBreakerWindowSeconds} + onCircuitBreakerWindowSecondsChange={setCircuitBreakerWindowSeconds} + circuitBreakerMinCalls={circuitBreakerMinCalls} + onCircuitBreakerMinCallsChange={setCircuitBreakerMinCalls} /> {submitError && ( diff --git a/ui/src/app/campaigns/new/page.tsx b/ui/src/app/campaigns/new/page.tsx index 7ef0754..0d22407 100644 --- a/ui/src/app/campaigns/new/page.tsx +++ b/ui/src/app/campaigns/new/page.tsx @@ -8,7 +8,7 @@ import { toast } from 'sonner'; import { createCampaignApiV1CampaignCreatePost, - getCampaignLimitsApiV1OrganizationsCampaignLimitsGet, + getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet, getWorkflowsSummaryApiV1WorkflowSummaryGet } from '@/client/sdk.gen'; import type { WorkflowSummaryResponse } from '@/client/types.gen'; @@ -72,6 +72,11 @@ export default function NewCampaignPage() { const [timeSlots, setTimeSlots] = useState([ { day_of_week: 0, start_time: '09:00', end_time: '17:00' }, ]); + // Circuit breaker config state + const [circuitBreakerEnabled, setCircuitBreakerEnabled] = useState(true); + const [circuitBreakerFailureThreshold, setCircuitBreakerFailureThreshold] = useState('50'); + const [circuitBreakerWindowSeconds, setCircuitBreakerWindowSeconds] = useState('120'); + const [circuitBreakerMinCalls, setCircuitBreakerMinCalls] = useState('5'); // Redirect if not authenticated useEffect(() => { @@ -104,11 +109,11 @@ export default function NewCampaignPage() { }, [user, getAccessToken]); // Fetch campaign limits - const fetchCampaignLimits = useCallback(async () => { + const fetchCampaignDefaults = useCallback(async () => { if (!user) return; try { const accessToken = await getAccessToken(); - const response = await getCampaignLimitsApiV1OrganizationsCampaignLimitsGet({ + const response = await getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet({ headers: { 'Authorization': `Bearer ${accessToken}`, } @@ -117,14 +122,56 @@ export default function NewCampaignPage() { if (response.data) { setOrgConcurrentLimit(response.data.concurrent_call_limit); setFromNumbersCount(response.data.from_numbers_count); - // Initialize retry config from defaults - const retryConfig = response.data.default_retry_config; - setRetryEnabled(retryConfig.enabled); - setMaxRetries(String(retryConfig.max_retries)); - setRetryDelaySeconds(String(retryConfig.retry_delay_seconds)); - setRetryOnBusy(retryConfig.retry_on_busy); - setRetryOnNoAnswer(retryConfig.retry_on_no_answer); - setRetryOnVoicemail(retryConfig.retry_on_voicemail); + + const last = (response.data as { last_campaign_settings?: { + retry_config?: { enabled: boolean; max_retries: number; retry_delay_seconds: number; retry_on_busy: boolean; retry_on_no_answer: boolean; retry_on_voicemail: boolean }; + max_concurrency?: number | null; + schedule_config?: { enabled: boolean; timezone: string; slots: TimeSlot[] } | null; + circuit_breaker?: { enabled: boolean; failure_threshold: number; window_seconds: number; min_calls_in_window: number } | null; + } | null }).last_campaign_settings; + + if (last) { + // Pre-populate from last campaign + if (last.retry_config) { + setRetryEnabled(last.retry_config.enabled); + setMaxRetries(String(last.retry_config.max_retries)); + setRetryDelaySeconds(String(last.retry_config.retry_delay_seconds)); + setRetryOnBusy(last.retry_config.retry_on_busy); + setRetryOnNoAnswer(last.retry_config.retry_on_no_answer); + setRetryOnVoicemail(last.retry_config.retry_on_voicemail); + } else { + const retryConfig = response.data.default_retry_config; + setRetryEnabled(retryConfig.enabled); + setMaxRetries(String(retryConfig.max_retries)); + setRetryDelaySeconds(String(retryConfig.retry_delay_seconds)); + setRetryOnBusy(retryConfig.retry_on_busy); + setRetryOnNoAnswer(retryConfig.retry_on_no_answer); + setRetryOnVoicemail(retryConfig.retry_on_voicemail); + } + if (last.max_concurrency) { + setMaxConcurrency(String(last.max_concurrency)); + } + if (last.schedule_config) { + setScheduleEnabled(last.schedule_config.enabled); + setScheduleTimezone(last.schedule_config.timezone); + setTimeSlots(last.schedule_config.slots); + } + if (last.circuit_breaker) { + setCircuitBreakerEnabled(last.circuit_breaker.enabled); + setCircuitBreakerFailureThreshold(String(Math.round(last.circuit_breaker.failure_threshold * 100))); + setCircuitBreakerWindowSeconds(String(last.circuit_breaker.window_seconds)); + setCircuitBreakerMinCalls(String(last.circuit_breaker.min_calls_in_window)); + } + } else { + // No previous campaign — use defaults + const retryConfig = response.data.default_retry_config; + setRetryEnabled(retryConfig.enabled); + setMaxRetries(String(retryConfig.max_retries)); + setRetryDelaySeconds(String(retryConfig.retry_delay_seconds)); + setRetryOnBusy(retryConfig.retry_on_busy); + setRetryOnNoAnswer(retryConfig.retry_on_no_answer); + setRetryOnVoicemail(retryConfig.retry_on_voicemail); + } } } catch (error) { console.error('Failed to fetch campaign limits:', error); @@ -135,9 +182,9 @@ export default function NewCampaignPage() { useEffect(() => { if (user) { fetchWorkflows(); - fetchCampaignLimits(); + fetchCampaignDefaults(); } - }, [fetchWorkflows, fetchCampaignLimits, user]); + }, [fetchWorkflows, fetchCampaignDefaults, user]); // Effective concurrency limit considering both org limit and available CLIs const effectiveLimit = fromNumbersCount > 0 @@ -195,6 +242,15 @@ export default function NewCampaignPage() { } : undefined; + // Build circuit_breaker config + const circuitBreakerConfig = { + enabled: circuitBreakerEnabled, + failure_threshold: (parseInt(circuitBreakerFailureThreshold) || 50) / 100, + window_seconds: parseInt(circuitBreakerWindowSeconds) || 120, + min_calls_in_window: parseInt(circuitBreakerMinCalls) || 5, + }; + + const response = await createCampaignApiV1CampaignCreatePost({ body: { name: campaignName, @@ -204,6 +260,7 @@ export default function NewCampaignPage() { retry_config: retryConfig, max_concurrency: maxConcurrencyValue, schedule_config: scheduleConfig, + circuit_breaker: circuitBreakerConfig, }, headers: { 'Authorization': `Bearer ${accessToken}`, @@ -401,6 +458,14 @@ export default function NewCampaignPage() { onScheduleTimezoneChange={setScheduleTimezone} timeSlots={timeSlots} onTimeSlotsChange={setTimeSlots} + circuitBreakerEnabled={circuitBreakerEnabled} + onCircuitBreakerEnabledChange={setCircuitBreakerEnabled} + circuitBreakerFailureThreshold={circuitBreakerFailureThreshold} + onCircuitBreakerFailureThresholdChange={setCircuitBreakerFailureThreshold} + circuitBreakerWindowSeconds={circuitBreakerWindowSeconds} + onCircuitBreakerWindowSecondsChange={setCircuitBreakerWindowSeconds} + circuitBreakerMinCalls={circuitBreakerMinCalls} + onCircuitBreakerMinCallsChange={setCircuitBreakerMinCalls} /> diff --git a/ui/src/app/files/DocumentUpload.tsx b/ui/src/app/files/DocumentUpload.tsx index e9367c3..4ff002d 100644 --- a/ui/src/app/files/DocumentUpload.tsx +++ b/ui/src/app/files/DocumentUpload.tsx @@ -17,7 +17,7 @@ interface DocumentUploadProps { onUploadSuccess: () => void; } -const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB +const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB const ACCEPTED_FILE_TYPES = ['.pdf', '.docx', '.doc', '.txt']; export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps) { @@ -36,7 +36,7 @@ export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps) // Validate file size if (file.size > MAX_FILE_SIZE) { - toast.error('File size must be less than 100MB'); + toast.error('File size must be less than 5MB'); return false; } @@ -44,7 +44,13 @@ export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps) }; const uploadFile = async (file: File) => { - if (!validateFile(file)) return; + if (!validateFile(file)) { + // Reset file input so the same file can be re-selected + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + return; + } setUploading(true); setUploadProgress(0); @@ -182,7 +188,7 @@ export default function DocumentUpload({ onUploadSuccess }: DocumentUploadProps) or click to browse

- Supported formats: {ACCEPTED_FILE_TYPES.join(', ')} (Max 100MB) + Supported formats: {ACCEPTED_FILE_TYPES.join(', ')} (Max 5MB)

diff --git a/ui/src/client/sdk.gen.ts b/ui/src/client/sdk.gen.ts index 0ffda7f..8062d69 100644 --- a/ui/src/client/sdk.gen.ts +++ b/ui/src/client/sdk.gen.ts @@ -3,7 +3,7 @@ import type { Client,Options as ClientOptions, TDataShape } from '@hey-api/client-fetch'; import { client as _heyApiClient } from './client.gen'; -import type { ArchiveApiKeyApiV1UserApiKeysApiKeyIdDeleteData, ArchiveApiKeyApiV1UserApiKeysApiKeyIdDeleteError, ArchiveApiKeyApiV1UserApiKeysApiKeyIdDeleteResponse, ArchiveServiceKeyApiV1UserServiceKeysServiceKeyIdDeleteData, ArchiveServiceKeyApiV1UserServiceKeysServiceKeyIdDeleteError, CompleteTransferFunctionCallApiV1TelephonyTransferResultTransferIdPostData, CompleteTransferFunctionCallApiV1TelephonyTransferResultTransferIdPostError, CreateApiKeyApiV1UserApiKeysPostData, CreateApiKeyApiV1UserApiKeysPostError, CreateApiKeyApiV1UserApiKeysPostResponse, CreateCampaignApiV1CampaignCreatePostData, CreateCampaignApiV1CampaignCreatePostError, CreateCampaignApiV1CampaignCreatePostResponse, CreateCredentialApiV1CredentialsPostData, CreateCredentialApiV1CredentialsPostError, CreateCredentialApiV1CredentialsPostResponse, CreateLoadTestApiV1LooptalkLoadTestsPostData, CreateLoadTestApiV1LooptalkLoadTestsPostError, CreateLoadTestApiV1LooptalkLoadTestsPostResponse, CreateOrUpdateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenPostData, CreateOrUpdateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenPostError, CreateOrUpdateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenPostResponse, CreateServiceKeyApiV1UserServiceKeysPostData, CreateServiceKeyApiV1UserServiceKeysPostError, CreateServiceKeyApiV1UserServiceKeysPostResponse, CreateSessionApiV1IntegrationSessionPostData, CreateSessionApiV1IntegrationSessionPostError, CreateSessionApiV1IntegrationSessionPostResponse, CreateTestSessionApiV1LooptalkTestSessionsPostData, CreateTestSessionApiV1LooptalkTestSessionsPostError, CreateTestSessionApiV1LooptalkTestSessionsPostResponse, CreateToolApiV1ToolsPostData, CreateToolApiV1ToolsPostError, CreateToolApiV1ToolsPostResponse, CreateWorkflowApiV1WorkflowCreateDefinitionPostData, CreateWorkflowApiV1WorkflowCreateDefinitionPostError, CreateWorkflowApiV1WorkflowCreateDefinitionPostResponse, CreateWorkflowFromTemplateApiV1WorkflowCreateTemplatePostData, CreateWorkflowFromTemplateApiV1WorkflowCreateTemplatePostError, CreateWorkflowFromTemplateApiV1WorkflowCreateTemplatePostResponse, CreateWorkflowRunApiV1WorkflowWorkflowIdRunsPostData, CreateWorkflowRunApiV1WorkflowWorkflowIdRunsPostError, CreateWorkflowRunApiV1WorkflowWorkflowIdRunsPostResponse, DeactivateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenDeleteData, DeactivateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenDeleteError, DeactivateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenDeleteResponse, DeleteCredentialApiV1CredentialsCredentialUuidDeleteData, DeleteCredentialApiV1CredentialsCredentialUuidDeleteError, DeleteCredentialApiV1CredentialsCredentialUuidDeleteResponse, DeleteDocumentApiV1KnowledgeBaseDocumentsDocumentUuidDeleteData, DeleteDocumentApiV1KnowledgeBaseDocumentsDocumentUuidDeleteError, DeleteToolApiV1ToolsToolUuidDeleteData, DeleteToolApiV1ToolsToolUuidDeleteError, DeleteToolApiV1ToolsToolUuidDeleteResponse, DownloadWorkflowArtifactApiV1PublicDownloadWorkflowTokenArtifactTypeGetData, DownloadWorkflowArtifactApiV1PublicDownloadWorkflowTokenArtifactTypeGetError, DuplicateWorkflowTemplateApiV1WorkflowTemplatesDuplicatePostData, DuplicateWorkflowTemplateApiV1WorkflowTemplatesDuplicatePostError, DuplicateWorkflowTemplateApiV1WorkflowTemplatesDuplicatePostResponse, GetActiveTestsApiV1LooptalkActiveTestsGetData, GetActiveTestsApiV1LooptalkActiveTestsGetError, GetApiKeysApiV1UserApiKeysGetData, GetApiKeysApiV1UserApiKeysGetError, GetApiKeysApiV1UserApiKeysGetResponse, GetAuthUserApiV1UserAuthUserGetData, GetAuthUserApiV1UserAuthUserGetError, GetAuthUserApiV1UserAuthUserGetResponse, GetCampaignApiV1CampaignCampaignIdGetData, GetCampaignApiV1CampaignCampaignIdGetError, GetCampaignApiV1CampaignCampaignIdGetResponse, GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetData, GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetError, GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponse, GetCampaignProgressApiV1CampaignCampaignIdProgressGetData, GetCampaignProgressApiV1CampaignCampaignIdProgressGetError, GetCampaignProgressApiV1CampaignCampaignIdProgressGetResponse, GetCampaignRunsApiV1CampaignCampaignIdRunsGetData, GetCampaignRunsApiV1CampaignCampaignIdRunsGetError, GetCampaignRunsApiV1CampaignCampaignIdRunsGetResponse, GetCampaignsApiV1CampaignGetData, GetCampaignsApiV1CampaignGetError, GetCampaignsApiV1CampaignGetResponse, GetCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGetData, GetCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGetError, GetCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGetResponse, GetCredentialApiV1CredentialsCredentialUuidGetData, GetCredentialApiV1CredentialsCredentialUuidGetError, GetCredentialApiV1CredentialsCredentialUuidGetResponse, GetCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGetData, GetCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGetError, GetCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGetResponse, GetCurrentUserApiV1AuthMeGetData, GetCurrentUserApiV1AuthMeGetError, GetCurrentUserApiV1AuthMeGetResponse, GetDailyReportApiV1OrganizationsReportsDailyGetData, GetDailyReportApiV1OrganizationsReportsDailyGetError, GetDailyReportApiV1OrganizationsReportsDailyGetResponse, GetDailyRunsDetailApiV1OrganizationsReportsDailyRunsGetData, GetDailyRunsDetailApiV1OrganizationsReportsDailyRunsGetError, GetDailyRunsDetailApiV1OrganizationsReportsDailyRunsGetResponse, GetDailyUsageBreakdownApiV1OrganizationsUsageDailyBreakdownGetData, GetDailyUsageBreakdownApiV1OrganizationsUsageDailyBreakdownGetError, GetDailyUsageBreakdownApiV1OrganizationsUsageDailyBreakdownGetResponse, GetDefaultConfigurationsApiV1UserConfigurationsDefaultsGetData, GetDefaultConfigurationsApiV1UserConfigurationsDefaultsGetResponse, GetDocumentApiV1KnowledgeBaseDocumentsDocumentUuidGetData, GetDocumentApiV1KnowledgeBaseDocumentsDocumentUuidGetError, GetDocumentApiV1KnowledgeBaseDocumentsDocumentUuidGetResponse, GetEmbedConfigApiV1PublicEmbedConfigTokenGetData, GetEmbedConfigApiV1PublicEmbedConfigTokenGetError, GetEmbedConfigApiV1PublicEmbedConfigTokenGetResponse, GetEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenGetData, GetEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenGetError, GetEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenGetResponse, GetFileMetadataApiV1S3FileMetadataGetData, GetFileMetadataApiV1S3FileMetadataGetError, GetFileMetadataApiV1S3FileMetadataGetResponse, GetIntegrationAccessTokenApiV1IntegrationIntegrationIdAccessTokenGetData, GetIntegrationAccessTokenApiV1IntegrationIntegrationIdAccessTokenGetError, GetIntegrationAccessTokenApiV1IntegrationIntegrationIdAccessTokenGetResponse, GetIntegrationsApiV1IntegrationGetData, GetIntegrationsApiV1IntegrationGetError, GetIntegrationsApiV1IntegrationGetResponse, GetLoadTestStatsApiV1LooptalkLoadTestsLoadTestGroupIdStatsGetData, GetLoadTestStatsApiV1LooptalkLoadTestsLoadTestGroupIdStatsGetError, GetLoadTestStatsApiV1LooptalkLoadTestsLoadTestGroupIdStatsGetResponse, GetPresignedUploadUrlApiV1S3PresignedUploadUrlPostData, GetPresignedUploadUrlApiV1S3PresignedUploadUrlPostError, GetPresignedUploadUrlApiV1S3PresignedUploadUrlPostResponse, GetPublicTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenGetData, GetPublicTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenGetError, GetPublicTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenGetResponse, GetServiceKeysApiV1UserServiceKeysGetData, GetServiceKeysApiV1UserServiceKeysGetError, GetServiceKeysApiV1UserServiceKeysGetResponse, GetSignedUrlApiV1S3SignedUrlGetData, GetSignedUrlApiV1S3SignedUrlGetError, GetSignedUrlApiV1S3SignedUrlGetResponse, GetTelephonyConfigurationApiV1OrganizationsTelephonyConfigGetData, GetTelephonyConfigurationApiV1OrganizationsTelephonyConfigGetError, GetTelephonyConfigurationApiV1OrganizationsTelephonyConfigGetResponse, GetTestSessionApiV1LooptalkTestSessionsTestSessionIdGetData, GetTestSessionApiV1LooptalkTestSessionsTestSessionIdGetError, GetTestSessionApiV1LooptalkTestSessionsTestSessionIdGetResponse, GetTestSessionConversationApiV1LooptalkTestSessionsTestSessionIdConversationGetData, GetTestSessionConversationApiV1LooptalkTestSessionsTestSessionIdConversationGetError, GetToolApiV1ToolsToolUuidGetData, GetToolApiV1ToolsToolUuidGetError, GetToolApiV1ToolsToolUuidGetResponse, GetTurnCredentialsApiV1TurnCredentialsGetData, GetTurnCredentialsApiV1TurnCredentialsGetError, GetTurnCredentialsApiV1TurnCredentialsGetResponse, GetUploadUrlApiV1KnowledgeBaseUploadUrlPostData, GetUploadUrlApiV1KnowledgeBaseUploadUrlPostError, GetUploadUrlApiV1KnowledgeBaseUploadUrlPostResponse, GetUsageHistoryApiV1OrganizationsUsageRunsGetData, GetUsageHistoryApiV1OrganizationsUsageRunsGetError, GetUsageHistoryApiV1OrganizationsUsageRunsGetResponse, GetUserConfigurationsApiV1UserConfigurationsUserGetData, GetUserConfigurationsApiV1UserConfigurationsUserGetError, GetUserConfigurationsApiV1UserConfigurationsUserGetResponse, GetVoicesApiV1UserConfigurationsVoicesProviderGetData, GetVoicesApiV1UserConfigurationsVoicesProviderGetError, GetVoicesApiV1UserConfigurationsVoicesProviderGetResponse, GetWorkflowApiV1WorkflowFetchWorkflowIdGetData, GetWorkflowApiV1WorkflowFetchWorkflowIdGetError, GetWorkflowApiV1WorkflowFetchWorkflowIdGetResponse, GetWorkflowCountApiV1WorkflowCountGetData, GetWorkflowCountApiV1WorkflowCountGetError, GetWorkflowCountApiV1WorkflowCountGetResponse, GetWorkflowOptionsApiV1OrganizationsReportsWorkflowsGetData, GetWorkflowOptionsApiV1OrganizationsReportsWorkflowsGetError, GetWorkflowOptionsApiV1OrganizationsReportsWorkflowsGetResponse, GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetData, GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetError, GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetResponse, GetWorkflowRunsApiV1SuperuserWorkflowRunsGetData, GetWorkflowRunsApiV1SuperuserWorkflowRunsGetError, GetWorkflowRunsApiV1SuperuserWorkflowRunsGetResponse, GetWorkflowRunsApiV1WorkflowWorkflowIdRunsGetData, GetWorkflowRunsApiV1WorkflowWorkflowIdRunsGetError, GetWorkflowRunsApiV1WorkflowWorkflowIdRunsGetResponse, GetWorkflowsApiV1WorkflowFetchGetData, GetWorkflowsApiV1WorkflowFetchGetError, GetWorkflowsApiV1WorkflowFetchGetResponse, GetWorkflowsSummaryApiV1WorkflowSummaryGetData, GetWorkflowsSummaryApiV1WorkflowSummaryGetError, GetWorkflowsSummaryApiV1WorkflowSummaryGetResponse, GetWorkflowTemplatesApiV1WorkflowTemplatesGetData, GetWorkflowTemplatesApiV1WorkflowTemplatesGetResponse, HandleCloudonixCdrApiV1TelephonyCloudonixCdrPostData, HandleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackWorkflowRunIdPostData, HandleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackWorkflowRunIdPostError, HandleInboundFallbackApiV1TelephonyInboundFallbackPostData, HandleInboundTelephonyApiV1TelephonyInboundWorkflowIdPostData, HandleInboundTelephonyApiV1TelephonyInboundWorkflowIdPostError, HandleTwilioStatusCallbackApiV1TelephonyTwilioStatusCallbackWorkflowRunIdPostData, HandleTwilioStatusCallbackApiV1TelephonyTwilioStatusCallbackWorkflowRunIdPostError, HandleVobizHangupCallbackApiV1TelephonyVobizHangupCallbackWorkflowRunIdPostData, HandleVobizHangupCallbackApiV1TelephonyVobizHangupCallbackWorkflowRunIdPostError, HandleVobizHangupCallbackByWorkflowApiV1TelephonyVobizHangupCallbackWorkflowWorkflowIdPostData, HandleVobizHangupCallbackByWorkflowApiV1TelephonyVobizHangupCallbackWorkflowWorkflowIdPostError, HandleVobizRingCallbackApiV1TelephonyVobizRingCallbackWorkflowRunIdPostData, HandleVobizRingCallbackApiV1TelephonyVobizRingCallbackWorkflowRunIdPostError, HandleVonageEventsApiV1TelephonyVonageEventsWorkflowRunIdPostData, HandleVonageEventsApiV1TelephonyVonageEventsWorkflowRunIdPostError, HealthApiV1HealthGetData, HealthApiV1HealthGetResponse,ImpersonateApiV1SuperuserImpersonatePostData, ImpersonateApiV1SuperuserImpersonatePostError, ImpersonateApiV1SuperuserImpersonatePostResponse, InitializeEmbedSessionApiV1PublicEmbedInitPostData, InitializeEmbedSessionApiV1PublicEmbedInitPostError, InitializeEmbedSessionApiV1PublicEmbedInitPostResponse, InitiateCallApiV1PublicAgentUuidPostData, InitiateCallApiV1PublicAgentUuidPostError, InitiateCallApiV1PublicAgentUuidPostResponse, InitiateCallApiV1TelephonyInitiateCallPostData, InitiateCallApiV1TelephonyInitiateCallPostError, InitiateCallTransferApiV1TelephonyCallTransferPostData, InitiateCallTransferApiV1TelephonyCallTransferPostError, ListCredentialsApiV1CredentialsGetData, ListCredentialsApiV1CredentialsGetError, ListCredentialsApiV1CredentialsGetResponse, ListDocumentsApiV1KnowledgeBaseDocumentsGetData, ListDocumentsApiV1KnowledgeBaseDocumentsGetError, ListDocumentsApiV1KnowledgeBaseDocumentsGetResponse, ListTestSessionsApiV1LooptalkTestSessionsGetData, ListTestSessionsApiV1LooptalkTestSessionsGetError, ListTestSessionsApiV1LooptalkTestSessionsGetResponse, ListToolsApiV1ToolsGetData, ListToolsApiV1ToolsGetError, ListToolsApiV1ToolsGetResponse, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostError, LoginApiV1AuthLoginPostResponse, OptionsConfigApiV1PublicEmbedConfigTokenOptionsData, OptionsConfigApiV1PublicEmbedConfigTokenOptionsError, OptionsInitApiV1PublicEmbedInitOptionsData, OptionsTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenOptionsData, OptionsTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenOptionsError, PauseCampaignApiV1CampaignCampaignIdPausePostData, PauseCampaignApiV1CampaignCampaignIdPausePostError, PauseCampaignApiV1CampaignCampaignIdPausePostResponse, ProcessDocumentApiV1KnowledgeBaseProcessDocumentPostData, ProcessDocumentApiV1KnowledgeBaseProcessDocumentPostError, ProcessDocumentApiV1KnowledgeBaseProcessDocumentPostResponse, ReactivateApiKeyApiV1UserApiKeysApiKeyIdReactivatePutData, ReactivateApiKeyApiV1UserApiKeysApiKeyIdReactivatePutError, ReactivateApiKeyApiV1UserApiKeysApiKeyIdReactivatePutResponse, ReactivateServiceKeyApiV1UserServiceKeysServiceKeyIdReactivatePutData, ReactivateServiceKeyApiV1UserServiceKeysServiceKeyIdReactivatePutError, ResumeCampaignApiV1CampaignCampaignIdResumePostData, ResumeCampaignApiV1CampaignCampaignIdResumePostError, ResumeCampaignApiV1CampaignCampaignIdResumePostResponse, SaveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPostData, SaveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPostError, SearchChunksApiV1KnowledgeBaseSearchPostData, SearchChunksApiV1KnowledgeBaseSearchPostError, SearchChunksApiV1KnowledgeBaseSearchPostResponse, SignupApiV1AuthSignupPostData, SignupApiV1AuthSignupPostError, SignupApiV1AuthSignupPostResponse, StartCampaignApiV1CampaignCampaignIdStartPostData, StartCampaignApiV1CampaignCampaignIdStartPostError, StartCampaignApiV1CampaignCampaignIdStartPostResponse, StartTestSessionApiV1LooptalkTestSessionsTestSessionIdStartPostData, StartTestSessionApiV1LooptalkTestSessionsTestSessionIdStartPostError, StopTestSessionApiV1LooptalkTestSessionsTestSessionIdStopPostData, StopTestSessionApiV1LooptalkTestSessionsTestSessionIdStopPostError, UnarchiveToolApiV1ToolsToolUuidUnarchivePostData, UnarchiveToolApiV1ToolsToolUuidUnarchivePostError, UnarchiveToolApiV1ToolsToolUuidUnarchivePostResponse, UpdateCampaignApiV1CampaignCampaignIdPatchData, UpdateCampaignApiV1CampaignCampaignIdPatchError, UpdateCampaignApiV1CampaignCampaignIdPatchResponse, UpdateCredentialApiV1CredentialsCredentialUuidPutData, UpdateCredentialApiV1CredentialsCredentialUuidPutError, UpdateCredentialApiV1CredentialsCredentialUuidPutResponse, UpdateIntegrationApiV1IntegrationIntegrationIdPutData, UpdateIntegrationApiV1IntegrationIntegrationIdPutError, UpdateIntegrationApiV1IntegrationIntegrationIdPutResponse, UpdateToolApiV1ToolsToolUuidPutData, UpdateToolApiV1ToolsToolUuidPutError, UpdateToolApiV1ToolsToolUuidPutResponse, UpdateUserConfigurationsApiV1UserConfigurationsUserPutData, UpdateUserConfigurationsApiV1UserConfigurationsUserPutError, UpdateUserConfigurationsApiV1UserConfigurationsUserPutResponse, UpdateWorkflowApiV1WorkflowWorkflowIdPutData, UpdateWorkflowApiV1WorkflowWorkflowIdPutError, UpdateWorkflowApiV1WorkflowWorkflowIdPutResponse, UpdateWorkflowStatusApiV1WorkflowWorkflowIdStatusPutData, UpdateWorkflowStatusApiV1WorkflowWorkflowIdStatusPutError, UpdateWorkflowStatusApiV1WorkflowWorkflowIdStatusPutResponse, ValidateUserConfigurationsApiV1UserConfigurationsUserValidateGetData, ValidateUserConfigurationsApiV1UserConfigurationsUserValidateGetError, ValidateUserConfigurationsApiV1UserConfigurationsUserValidateGetResponse, ValidateWorkflowApiV1WorkflowWorkflowIdValidatePostData, ValidateWorkflowApiV1WorkflowWorkflowIdValidatePostError, ValidateWorkflowApiV1WorkflowWorkflowIdValidatePostResponse } from './types.gen'; +import type { ArchiveApiKeyApiV1UserApiKeysApiKeyIdDeleteData, ArchiveApiKeyApiV1UserApiKeysApiKeyIdDeleteError, ArchiveApiKeyApiV1UserApiKeysApiKeyIdDeleteResponse, ArchiveServiceKeyApiV1UserServiceKeysServiceKeyIdDeleteData, ArchiveServiceKeyApiV1UserServiceKeysServiceKeyIdDeleteError, CompleteTransferFunctionCallApiV1TelephonyTransferResultTransferIdPostData, CompleteTransferFunctionCallApiV1TelephonyTransferResultTransferIdPostError, CreateApiKeyApiV1UserApiKeysPostData, CreateApiKeyApiV1UserApiKeysPostError, CreateApiKeyApiV1UserApiKeysPostResponse, CreateCampaignApiV1CampaignCreatePostData, CreateCampaignApiV1CampaignCreatePostError, CreateCampaignApiV1CampaignCreatePostResponse, CreateCredentialApiV1CredentialsPostData, CreateCredentialApiV1CredentialsPostError, CreateCredentialApiV1CredentialsPostResponse, CreateLoadTestApiV1LooptalkLoadTestsPostData, CreateLoadTestApiV1LooptalkLoadTestsPostError, CreateLoadTestApiV1LooptalkLoadTestsPostResponse, CreateOrUpdateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenPostData, CreateOrUpdateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenPostError, CreateOrUpdateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenPostResponse, CreateServiceKeyApiV1UserServiceKeysPostData, CreateServiceKeyApiV1UserServiceKeysPostError, CreateServiceKeyApiV1UserServiceKeysPostResponse, CreateSessionApiV1IntegrationSessionPostData, CreateSessionApiV1IntegrationSessionPostError, CreateSessionApiV1IntegrationSessionPostResponse, CreateTestSessionApiV1LooptalkTestSessionsPostData, CreateTestSessionApiV1LooptalkTestSessionsPostError, CreateTestSessionApiV1LooptalkTestSessionsPostResponse, CreateToolApiV1ToolsPostData, CreateToolApiV1ToolsPostError, CreateToolApiV1ToolsPostResponse, CreateWorkflowApiV1WorkflowCreateDefinitionPostData, CreateWorkflowApiV1WorkflowCreateDefinitionPostError, CreateWorkflowApiV1WorkflowCreateDefinitionPostResponse, CreateWorkflowFromTemplateApiV1WorkflowCreateTemplatePostData, CreateWorkflowFromTemplateApiV1WorkflowCreateTemplatePostError, CreateWorkflowFromTemplateApiV1WorkflowCreateTemplatePostResponse, CreateWorkflowRunApiV1WorkflowWorkflowIdRunsPostData, CreateWorkflowRunApiV1WorkflowWorkflowIdRunsPostError, CreateWorkflowRunApiV1WorkflowWorkflowIdRunsPostResponse, DeactivateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenDeleteData, DeactivateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenDeleteError, DeactivateEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenDeleteResponse, DeleteCredentialApiV1CredentialsCredentialUuidDeleteData, DeleteCredentialApiV1CredentialsCredentialUuidDeleteError, DeleteCredentialApiV1CredentialsCredentialUuidDeleteResponse, DeleteDocumentApiV1KnowledgeBaseDocumentsDocumentUuidDeleteData, DeleteDocumentApiV1KnowledgeBaseDocumentsDocumentUuidDeleteError, DeleteToolApiV1ToolsToolUuidDeleteData, DeleteToolApiV1ToolsToolUuidDeleteError, DeleteToolApiV1ToolsToolUuidDeleteResponse, DownloadWorkflowArtifactApiV1PublicDownloadWorkflowTokenArtifactTypeGetData, DownloadWorkflowArtifactApiV1PublicDownloadWorkflowTokenArtifactTypeGetError, DuplicateWorkflowTemplateApiV1WorkflowTemplatesDuplicatePostData, DuplicateWorkflowTemplateApiV1WorkflowTemplatesDuplicatePostError, DuplicateWorkflowTemplateApiV1WorkflowTemplatesDuplicatePostResponse, GetActiveTestsApiV1LooptalkActiveTestsGetData, GetActiveTestsApiV1LooptalkActiveTestsGetError, GetApiKeysApiV1UserApiKeysGetData, GetApiKeysApiV1UserApiKeysGetError, GetApiKeysApiV1UserApiKeysGetResponse, GetAuthUserApiV1UserAuthUserGetData, GetAuthUserApiV1UserAuthUserGetError, GetAuthUserApiV1UserAuthUserGetResponse, GetCampaignApiV1CampaignCampaignIdGetData, GetCampaignApiV1CampaignCampaignIdGetError, GetCampaignApiV1CampaignCampaignIdGetResponse, GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetData, GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetError, GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponse, GetCampaignProgressApiV1CampaignCampaignIdProgressGetData, GetCampaignProgressApiV1CampaignCampaignIdProgressGetError, GetCampaignProgressApiV1CampaignCampaignIdProgressGetResponse, GetCampaignRunsApiV1CampaignCampaignIdRunsGetData, GetCampaignRunsApiV1CampaignCampaignIdRunsGetError, GetCampaignRunsApiV1CampaignCampaignIdRunsGetResponse, GetCampaignsApiV1CampaignGetData, GetCampaignsApiV1CampaignGetError, GetCampaignsApiV1CampaignGetResponse, GetCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGetData, GetCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGetError, GetCampaignSourceDownloadUrlApiV1CampaignCampaignIdSourceDownloadUrlGetResponse, GetCredentialApiV1CredentialsCredentialUuidGetData, GetCredentialApiV1CredentialsCredentialUuidGetError, GetCredentialApiV1CredentialsCredentialUuidGetResponse, GetCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGetData, GetCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGetError, GetCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGetResponse, GetCurrentUserApiV1AuthMeGetData, GetCurrentUserApiV1AuthMeGetError, GetCurrentUserApiV1AuthMeGetResponse, GetDailyReportApiV1OrganizationsReportsDailyGetData, GetDailyReportApiV1OrganizationsReportsDailyGetError, GetDailyReportApiV1OrganizationsReportsDailyGetResponse, GetDailyRunsDetailApiV1OrganizationsReportsDailyRunsGetData, GetDailyRunsDetailApiV1OrganizationsReportsDailyRunsGetError, GetDailyRunsDetailApiV1OrganizationsReportsDailyRunsGetResponse, GetDailyUsageBreakdownApiV1OrganizationsUsageDailyBreakdownGetData, GetDailyUsageBreakdownApiV1OrganizationsUsageDailyBreakdownGetError, GetDailyUsageBreakdownApiV1OrganizationsUsageDailyBreakdownGetResponse, GetDefaultConfigurationsApiV1UserConfigurationsDefaultsGetData, GetDefaultConfigurationsApiV1UserConfigurationsDefaultsGetResponse, GetDocumentApiV1KnowledgeBaseDocumentsDocumentUuidGetData, GetDocumentApiV1KnowledgeBaseDocumentsDocumentUuidGetError, GetDocumentApiV1KnowledgeBaseDocumentsDocumentUuidGetResponse, GetEmbedConfigApiV1PublicEmbedConfigTokenGetData, GetEmbedConfigApiV1PublicEmbedConfigTokenGetError, GetEmbedConfigApiV1PublicEmbedConfigTokenGetResponse, GetEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenGetData, GetEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenGetError, GetEmbedTokenApiV1WorkflowWorkflowIdEmbedTokenGetResponse, GetFileMetadataApiV1S3FileMetadataGetData, GetFileMetadataApiV1S3FileMetadataGetError, GetFileMetadataApiV1S3FileMetadataGetResponse, GetIntegrationAccessTokenApiV1IntegrationIntegrationIdAccessTokenGetData, GetIntegrationAccessTokenApiV1IntegrationIntegrationIdAccessTokenGetError, GetIntegrationAccessTokenApiV1IntegrationIntegrationIdAccessTokenGetResponse, GetIntegrationsApiV1IntegrationGetData, GetIntegrationsApiV1IntegrationGetError, GetIntegrationsApiV1IntegrationGetResponse, GetLoadTestStatsApiV1LooptalkLoadTestsLoadTestGroupIdStatsGetData, GetLoadTestStatsApiV1LooptalkLoadTestsLoadTestGroupIdStatsGetError, GetLoadTestStatsApiV1LooptalkLoadTestsLoadTestGroupIdStatsGetResponse, GetPresignedUploadUrlApiV1S3PresignedUploadUrlPostData, GetPresignedUploadUrlApiV1S3PresignedUploadUrlPostError, GetPresignedUploadUrlApiV1S3PresignedUploadUrlPostResponse, GetPublicTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenGetData, GetPublicTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenGetError, GetPublicTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenGetResponse, GetServiceKeysApiV1UserServiceKeysGetData, GetServiceKeysApiV1UserServiceKeysGetError, GetServiceKeysApiV1UserServiceKeysGetResponse, GetSignedUrlApiV1S3SignedUrlGetData, GetSignedUrlApiV1S3SignedUrlGetError, GetSignedUrlApiV1S3SignedUrlGetResponse, GetTelephonyConfigurationApiV1OrganizationsTelephonyConfigGetData, GetTelephonyConfigurationApiV1OrganizationsTelephonyConfigGetError, GetTelephonyConfigurationApiV1OrganizationsTelephonyConfigGetResponse, GetTestSessionApiV1LooptalkTestSessionsTestSessionIdGetData, GetTestSessionApiV1LooptalkTestSessionsTestSessionIdGetError, GetTestSessionApiV1LooptalkTestSessionsTestSessionIdGetResponse, GetTestSessionConversationApiV1LooptalkTestSessionsTestSessionIdConversationGetData, GetTestSessionConversationApiV1LooptalkTestSessionsTestSessionIdConversationGetError, GetToolApiV1ToolsToolUuidGetData, GetToolApiV1ToolsToolUuidGetError, GetToolApiV1ToolsToolUuidGetResponse, GetTurnCredentialsApiV1TurnCredentialsGetData, GetTurnCredentialsApiV1TurnCredentialsGetError, GetTurnCredentialsApiV1TurnCredentialsGetResponse, GetUploadUrlApiV1KnowledgeBaseUploadUrlPostData, GetUploadUrlApiV1KnowledgeBaseUploadUrlPostError, GetUploadUrlApiV1KnowledgeBaseUploadUrlPostResponse, GetUsageHistoryApiV1OrganizationsUsageRunsGetData, GetUsageHistoryApiV1OrganizationsUsageRunsGetError, GetUsageHistoryApiV1OrganizationsUsageRunsGetResponse, GetUserConfigurationsApiV1UserConfigurationsUserGetData, GetUserConfigurationsApiV1UserConfigurationsUserGetError, GetUserConfigurationsApiV1UserConfigurationsUserGetResponse, GetVoicesApiV1UserConfigurationsVoicesProviderGetData, GetVoicesApiV1UserConfigurationsVoicesProviderGetError, GetVoicesApiV1UserConfigurationsVoicesProviderGetResponse, GetWorkflowApiV1WorkflowFetchWorkflowIdGetData, GetWorkflowApiV1WorkflowFetchWorkflowIdGetError, GetWorkflowApiV1WorkflowFetchWorkflowIdGetResponse, GetWorkflowCountApiV1WorkflowCountGetData, GetWorkflowCountApiV1WorkflowCountGetError, GetWorkflowCountApiV1WorkflowCountGetResponse, GetWorkflowOptionsApiV1OrganizationsReportsWorkflowsGetData, GetWorkflowOptionsApiV1OrganizationsReportsWorkflowsGetError, GetWorkflowOptionsApiV1OrganizationsReportsWorkflowsGetResponse, GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetData, GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetError, GetWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGetResponse, GetWorkflowRunsApiV1SuperuserWorkflowRunsGetData, GetWorkflowRunsApiV1SuperuserWorkflowRunsGetError, GetWorkflowRunsApiV1SuperuserWorkflowRunsGetResponse, GetWorkflowRunsApiV1WorkflowWorkflowIdRunsGetData, GetWorkflowRunsApiV1WorkflowWorkflowIdRunsGetError, GetWorkflowRunsApiV1WorkflowWorkflowIdRunsGetResponse, GetWorkflowsApiV1WorkflowFetchGetData, GetWorkflowsApiV1WorkflowFetchGetError, GetWorkflowsApiV1WorkflowFetchGetResponse, GetWorkflowsSummaryApiV1WorkflowSummaryGetData, GetWorkflowsSummaryApiV1WorkflowSummaryGetError, GetWorkflowsSummaryApiV1WorkflowSummaryGetResponse, GetWorkflowTemplatesApiV1WorkflowTemplatesGetData, GetWorkflowTemplatesApiV1WorkflowTemplatesGetResponse, HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostData, HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostError, HandleCloudonixCdrApiV1TelephonyCloudonixCdrPostData, HandleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackWorkflowRunIdPostData, HandleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackWorkflowRunIdPostError, HandleInboundFallbackApiV1TelephonyInboundFallbackPostData, HandleInboundTelephonyApiV1TelephonyInboundWorkflowIdPostData, HandleInboundTelephonyApiV1TelephonyInboundWorkflowIdPostError, HandleTwilioStatusCallbackApiV1TelephonyTwilioStatusCallbackWorkflowRunIdPostData, HandleTwilioStatusCallbackApiV1TelephonyTwilioStatusCallbackWorkflowRunIdPostError, HandleVobizHangupCallbackApiV1TelephonyVobizHangupCallbackWorkflowRunIdPostData, HandleVobizHangupCallbackApiV1TelephonyVobizHangupCallbackWorkflowRunIdPostError, HandleVobizHangupCallbackByWorkflowApiV1TelephonyVobizHangupCallbackWorkflowWorkflowIdPostData, HandleVobizHangupCallbackByWorkflowApiV1TelephonyVobizHangupCallbackWorkflowWorkflowIdPostError, HandleVobizRingCallbackApiV1TelephonyVobizRingCallbackWorkflowRunIdPostData, HandleVobizRingCallbackApiV1TelephonyVobizRingCallbackWorkflowRunIdPostError, HandleVonageEventsApiV1TelephonyVonageEventsWorkflowRunIdPostData, HandleVonageEventsApiV1TelephonyVonageEventsWorkflowRunIdPostError, HealthApiV1HealthGetData, HealthApiV1HealthGetResponse,ImpersonateApiV1SuperuserImpersonatePostData, ImpersonateApiV1SuperuserImpersonatePostError, ImpersonateApiV1SuperuserImpersonatePostResponse, InitializeEmbedSessionApiV1PublicEmbedInitPostData, InitializeEmbedSessionApiV1PublicEmbedInitPostError, InitializeEmbedSessionApiV1PublicEmbedInitPostResponse, InitiateCallApiV1PublicAgentUuidPostData, InitiateCallApiV1PublicAgentUuidPostError, InitiateCallApiV1PublicAgentUuidPostResponse, InitiateCallApiV1TelephonyInitiateCallPostData, InitiateCallApiV1TelephonyInitiateCallPostError, InitiateCallTransferApiV1TelephonyCallTransferPostData, InitiateCallTransferApiV1TelephonyCallTransferPostError, ListCredentialsApiV1CredentialsGetData, ListCredentialsApiV1CredentialsGetError, ListCredentialsApiV1CredentialsGetResponse, ListDocumentsApiV1KnowledgeBaseDocumentsGetData, ListDocumentsApiV1KnowledgeBaseDocumentsGetError, ListDocumentsApiV1KnowledgeBaseDocumentsGetResponse, ListTestSessionsApiV1LooptalkTestSessionsGetData, ListTestSessionsApiV1LooptalkTestSessionsGetError, ListTestSessionsApiV1LooptalkTestSessionsGetResponse, ListToolsApiV1ToolsGetData, ListToolsApiV1ToolsGetError, ListToolsApiV1ToolsGetResponse, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostError, LoginApiV1AuthLoginPostResponse, OptionsConfigApiV1PublicEmbedConfigTokenOptionsData, OptionsConfigApiV1PublicEmbedConfigTokenOptionsError, OptionsInitApiV1PublicEmbedInitOptionsData, OptionsTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenOptionsData, OptionsTurnCredentialsApiV1PublicEmbedTurnCredentialsSessionTokenOptionsError, PauseCampaignApiV1CampaignCampaignIdPausePostData, PauseCampaignApiV1CampaignCampaignIdPausePostError, PauseCampaignApiV1CampaignCampaignIdPausePostResponse, ProcessDocumentApiV1KnowledgeBaseProcessDocumentPostData, ProcessDocumentApiV1KnowledgeBaseProcessDocumentPostError, ProcessDocumentApiV1KnowledgeBaseProcessDocumentPostResponse, ReactivateApiKeyApiV1UserApiKeysApiKeyIdReactivatePutData, ReactivateApiKeyApiV1UserApiKeysApiKeyIdReactivatePutError, ReactivateApiKeyApiV1UserApiKeysApiKeyIdReactivatePutResponse, ReactivateServiceKeyApiV1UserServiceKeysServiceKeyIdReactivatePutData, ReactivateServiceKeyApiV1UserServiceKeysServiceKeyIdReactivatePutError, ResumeCampaignApiV1CampaignCampaignIdResumePostData, ResumeCampaignApiV1CampaignCampaignIdResumePostError, ResumeCampaignApiV1CampaignCampaignIdResumePostResponse, SaveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPostData, SaveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPostError, SearchChunksApiV1KnowledgeBaseSearchPostData, SearchChunksApiV1KnowledgeBaseSearchPostError, SearchChunksApiV1KnowledgeBaseSearchPostResponse, SignupApiV1AuthSignupPostData, SignupApiV1AuthSignupPostError, SignupApiV1AuthSignupPostResponse, StartCampaignApiV1CampaignCampaignIdStartPostData, StartCampaignApiV1CampaignCampaignIdStartPostError, StartCampaignApiV1CampaignCampaignIdStartPostResponse, StartTestSessionApiV1LooptalkTestSessionsTestSessionIdStartPostData, StartTestSessionApiV1LooptalkTestSessionsTestSessionIdStartPostError, StopTestSessionApiV1LooptalkTestSessionsTestSessionIdStopPostData, StopTestSessionApiV1LooptalkTestSessionsTestSessionIdStopPostError, UnarchiveToolApiV1ToolsToolUuidUnarchivePostData, UnarchiveToolApiV1ToolsToolUuidUnarchivePostError, UnarchiveToolApiV1ToolsToolUuidUnarchivePostResponse, UpdateCampaignApiV1CampaignCampaignIdPatchData, UpdateCampaignApiV1CampaignCampaignIdPatchError, UpdateCampaignApiV1CampaignCampaignIdPatchResponse, UpdateCredentialApiV1CredentialsCredentialUuidPutData, UpdateCredentialApiV1CredentialsCredentialUuidPutError, UpdateCredentialApiV1CredentialsCredentialUuidPutResponse, UpdateIntegrationApiV1IntegrationIntegrationIdPutData, UpdateIntegrationApiV1IntegrationIntegrationIdPutError, UpdateIntegrationApiV1IntegrationIntegrationIdPutResponse, UpdateToolApiV1ToolsToolUuidPutData, UpdateToolApiV1ToolsToolUuidPutError, UpdateToolApiV1ToolsToolUuidPutResponse, UpdateUserConfigurationsApiV1UserConfigurationsUserPutData, UpdateUserConfigurationsApiV1UserConfigurationsUserPutError, UpdateUserConfigurationsApiV1UserConfigurationsUserPutResponse, UpdateWorkflowApiV1WorkflowWorkflowIdPutData, UpdateWorkflowApiV1WorkflowWorkflowIdPutError, UpdateWorkflowApiV1WorkflowWorkflowIdPutResponse, UpdateWorkflowStatusApiV1WorkflowWorkflowIdStatusPutData, UpdateWorkflowStatusApiV1WorkflowWorkflowIdStatusPutError, UpdateWorkflowStatusApiV1WorkflowWorkflowIdStatusPutResponse, ValidateUserConfigurationsApiV1UserConfigurationsUserValidateGetData, ValidateUserConfigurationsApiV1UserConfigurationsUserValidateGetError, ValidateUserConfigurationsApiV1UserConfigurationsUserValidateGetResponse, ValidateWorkflowApiV1WorkflowWorkflowIdValidatePostData, ValidateWorkflowApiV1WorkflowWorkflowIdValidatePostError, ValidateWorkflowApiV1WorkflowWorkflowIdValidatePostResponse } from './types.gen'; export type Options = ClientOptions & { /** @@ -100,6 +100,18 @@ export const handleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackW }); }; +/** + * Handle Cloudonix Amd Callback + * Handle Cloudonix-specific Answering Machine Detection(AMD) callbacks. + * Cloudonix sends AMD updates to the callback URL specified during call initiation. + */ +export const handleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPost = (options: Options) => { + return (options.client ?? _heyApiClient).post({ + url: '/api/v1/telephony/cloudonix/amd-callback/{workflow_run_id}', + ...options + }); +}; + /** * Handle Vobiz Hangup Callback By Workflow * Handle Vobiz hangup callback with workflow_id - finds workflow run by call_id. @@ -991,14 +1003,14 @@ export const saveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPost = < }; /** - * Get Campaign Limits + * Get Campaign Defaults * Get campaign limits for the user's organization. * * Returns the organization's concurrent call limit and default retry configuration. */ -export const getCampaignLimitsApiV1OrganizationsCampaignLimitsGet = (options?: Options) => { - return (options?.client ?? _heyApiClient).get({ - url: '/api/v1/organizations/campaign-limits', +export const getCampaignDefaultsApiV1OrganizationsCampaignDefaultsGet = (options?: Options) => { + return (options?.client ?? _heyApiClient).get({ + url: '/api/v1/organizations/campaign-defaults', ...options }); }; diff --git a/ui/src/client/types.gen.ts b/ui/src/client/types.gen.ts index 31875ff..b9a51ae 100644 --- a/ui/src/client/types.gen.ts +++ b/ui/src/client/types.gen.ts @@ -82,10 +82,11 @@ export type AuthUserResponse = { export type CallType = 'inbound' | 'outbound'; -export type CampaignLimitsResponse = { +export type CampaignDefaultsResponse = { concurrent_call_limit: number; from_numbers_count: number; default_retry_config: RetryConfigResponse; + last_campaign_settings?: LastCampaignSettingsResponse | null; }; export type CampaignProgressResponse = { @@ -120,6 +121,7 @@ export type CampaignResponse = { retry_config: RetryConfigResponse; max_concurrency?: number | null; schedule_config?: ScheduleConfigResponse | null; + circuit_breaker?: CircuitBreakerConfigResponse | null; }; /** @@ -192,6 +194,20 @@ export type ChunkSearchResponseSchema = { total_results: number; }; +export type CircuitBreakerConfigRequest = { + enabled?: boolean; + failure_threshold?: number; + window_seconds?: number; + min_calls_in_window?: number; +}; + +export type CircuitBreakerConfigResponse = { + enabled: boolean; + failure_threshold: number; + window_seconds: number; + min_calls_in_window: number; +}; + /** * Request schema for Cloudonix configuration. */ @@ -241,6 +257,7 @@ export type CreateCampaignRequest = { retry_config?: RetryConfigRequest | null; max_concurrency?: number | null; schedule_config?: ScheduleConfigRequest | null; + circuit_breaker?: CircuitBreakerConfigRequest | null; }; /** @@ -715,6 +732,13 @@ export type IntegrationResponse = { export type ItemKind = 'node' | 'edge' | 'workflow'; +export type LastCampaignSettingsResponse = { + retry_config?: RetryConfigResponse | null; + max_concurrency?: number | null; + schedule_config?: ScheduleConfigResponse | null; + circuit_breaker?: CircuitBreakerConfigResponse | null; +}; + export type LoadTestStatsResponse = { total: number; pending: number; @@ -949,7 +973,7 @@ export type ToolResponse = { */ export type TransferCallConfig = { /** - * Phone number to transfer the call to (E.164 format, e.g., +1234567890) + * Phone number or SIP endpoint to transfer the call to (E.164 format e.g., +1234567890, or SIP endpoint e.g., PJSIP/1234) */ destination: string; /** @@ -1058,6 +1082,7 @@ export type UpdateCampaignRequest = { retry_config?: RetryConfigRequest | null; max_concurrency?: number | null; schedule_config?: ScheduleConfigRequest | null; + circuit_breaker?: CircuitBreakerConfigRequest | null; }; /** @@ -1574,6 +1599,35 @@ export type HandleCloudonixStatusCallbackApiV1TelephonyCloudonixStatusCallbackWo 200: unknown; }; +export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostData = { + body?: never; + path: { + workflow_run_id: number; + }; + query?: never; + url: '/api/v1/telephony/cloudonix/amd-callback/{workflow_run_id}'; +}; + +export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostErrors = { + /** + * Not found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostError = HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostErrors[keyof HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostErrors]; + +export type HandleCloudonixAmdCallbackApiV1TelephonyCloudonixAmdCallbackWorkflowRunIdPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + export type HandleVobizHangupCallbackByWorkflowApiV1TelephonyVobizHangupCallbackWorkflowWorkflowIdPostData = { body?: never; headers?: { @@ -3593,7 +3647,7 @@ export type SaveTelephonyConfigurationApiV1OrganizationsTelephonyConfigPostRespo 200: unknown; }; -export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetData = { +export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetData = { body?: never; headers?: { authorization?: string | null; @@ -3601,10 +3655,10 @@ export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetData = { }; path?: never; query?: never; - url: '/api/v1/organizations/campaign-limits'; + url: '/api/v1/organizations/campaign-defaults'; }; -export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors = { +export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetErrors = { /** * Not found */ @@ -3615,16 +3669,16 @@ export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors = { 422: HttpValidationError; }; -export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetError = GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors[keyof GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetErrors]; +export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetError = GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetErrors[keyof GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetErrors]; -export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponses = { +export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponses = { /** * Successful Response */ - 200: CampaignLimitsResponse; + 200: CampaignDefaultsResponse; }; -export type GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponse = GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponses[keyof GetCampaignLimitsApiV1OrganizationsCampaignLimitsGetResponses]; +export type GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponse = GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponses[keyof GetCampaignDefaultsApiV1OrganizationsCampaignDefaultsGetResponses]; export type GetSignedUrlApiV1S3SignedUrlGetData = { body?: never;