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
+
+
+
+
+ )}
+
);
}
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;