mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-22 11:51:04 +02:00
* ViciDial Working * feat(telephony): add FreeSWITCH provider to upstream-PBX seam Generalize the upstream-PBX capture and control paths to dispatch by provider. FreeSWITCH bridges in with X-PBX-* headers and is driven over the Event Socket Library (uuid_kill / uuid_transfer) by the channel UUID, alongside the existing VICIdial ra_call_control path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * add vici specific configs * feat(telephony): env-based VICIdial config + address3 post-call routing Move VICIdial agent/non-agent API and FreeSWITCH ESL connection settings out of hardcoded POC values into environment variables so the same image works against a PBX on another server. Add VICIdial update_lead forwarding: X-VICI-UPDATE-LEAD_* extracted variables are mapped to lead columns and pushed via the non-agent API before a transfer, with reserved API-control params dropped. Add hardcoded address3 disposition routing (Y/N -> in-group transfer, else hang up) and a synchronous final variable extraction so the transfer path sees the freshest conversation state. Skip upstream_pbx capture on non-PJSIP channels to avoid Asterisk 500s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: run formatter * feat: make vici configurable from UI * chore: clean up PR * fix: incorporate review comments * chore: incorporate review comments * chore: generate client * chore: incporporate review comments * chore: incorporate review comments --------- Co-authored-by: Dograh POC <payment@dograh.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
91 lines
3 KiB
Python
91 lines
3 KiB
Python
import pytest
|
|
|
|
from api.schemas.tool import TransferCallConfig
|
|
|
|
|
|
def test_transfer_call_destination_accepts_initial_context_template():
|
|
config = TransferCallConfig(
|
|
destination="{{initial_context.transfer_destination}}",
|
|
)
|
|
|
|
assert config.destination == "{{initial_context.transfer_destination}}"
|
|
|
|
|
|
def test_transfer_call_destination_accepts_provider_specific_literal():
|
|
config = TransferCallConfig(destination="provider-specific-destination")
|
|
|
|
assert config.destination == "provider-specific-destination"
|
|
|
|
|
|
def test_transfer_call_static_allows_empty_draft_destination():
|
|
config = TransferCallConfig(destination_source="static", destination="")
|
|
|
|
assert config.destination_source == "static"
|
|
assert config.destination == ""
|
|
|
|
|
|
def test_transfer_call_dynamic_requires_resolver():
|
|
with pytest.raises(ValueError, match="resolver is required"):
|
|
TransferCallConfig(destination_source="dynamic", destination="")
|
|
|
|
|
|
def test_transfer_call_dynamic_accepts_resolver_without_destination():
|
|
config = TransferCallConfig(
|
|
destination_source="dynamic",
|
|
destination="",
|
|
resolver={
|
|
"type": "http",
|
|
"url": "https://crm.example.com/resolve-transfer",
|
|
},
|
|
)
|
|
|
|
assert config.destination_source == "dynamic"
|
|
assert config.destination == ""
|
|
assert config.resolver is not None
|
|
|
|
|
|
def test_transfer_call_context_mapping_requires_mapping():
|
|
with pytest.raises(ValueError, match="context_mapping is required"):
|
|
TransferCallConfig(destination_source="context_mapping")
|
|
|
|
|
|
def test_transfer_call_context_mapping_accepts_unique_routes():
|
|
config = TransferCallConfig(
|
|
destination_source="context_mapping",
|
|
context_mapping={
|
|
"context_path": "qualified",
|
|
"routes": [
|
|
{"context_value": "yes", "destination": "sales"},
|
|
{"context_value": "no", "destination": "support"},
|
|
],
|
|
"fallback_destination": "source",
|
|
},
|
|
)
|
|
|
|
assert config.context_mapping is not None
|
|
assert config.context_mapping.routes[0].destination == "sales"
|
|
|
|
|
|
def test_transfer_call_context_mapping_rejects_blank_context_path():
|
|
with pytest.raises(ValueError, match="context path cannot be blank"):
|
|
TransferCallConfig(
|
|
destination_source="context_mapping",
|
|
context_mapping={
|
|
"context_path": " ",
|
|
"routes": [{"context_value": "yes", "destination": "sales"}],
|
|
},
|
|
)
|
|
|
|
|
|
def test_transfer_call_context_mapping_rejects_duplicate_values_case_insensitively():
|
|
with pytest.raises(ValueError, match="must be unique"):
|
|
TransferCallConfig(
|
|
destination_source="context_mapping",
|
|
context_mapping={
|
|
"context_path": "qualified",
|
|
"routes": [
|
|
{"context_value": "Yes", "destination": "sales"},
|
|
{"context_value": "yes", "destination": "support"},
|
|
],
|
|
},
|
|
)
|