fix(proxy): pass the ApiPilot catalog with the correct argument
This commit is contained in:
@@ -9,7 +9,7 @@ from pathlib import Path
|
||||
import sys
|
||||
import threading
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import ANY, AsyncMock, Mock, patch
|
||||
|
||||
import httpx
|
||||
from fastapi.testclient import TestClient
|
||||
@@ -173,6 +173,65 @@ class BackendContractTests(unittest.TestCase):
|
||||
|
||||
|
||||
class VoiceProxyTests(unittest.TestCase):
|
||||
def test_apipilot_catalog_and_caller_defaults_reach_the_voice_session(self):
|
||||
closed = threading.Event()
|
||||
catalog = AsyncMock(return_value=[{
|
||||
"name": "get_caller_briefing",
|
||||
"description": "Retrieve the caller's local test briefing.",
|
||||
"requires_auth": True,
|
||||
"parameters": {"required": ["phone", "episode_id", "email"]},
|
||||
}])
|
||||
login = AsyncMock(return_value=("fixture-token", {}))
|
||||
profile = AsyncMock(return_value={"user": {"email": "caller@example.test"}})
|
||||
|
||||
def voice(socket):
|
||||
try:
|
||||
socket.send(json.dumps({"type": "session.created"}))
|
||||
for frame in socket:
|
||||
socket.send(frame)
|
||||
finally:
|
||||
closed.set()
|
||||
|
||||
with serve(voice, "127.0.0.1", 0) as upstream:
|
||||
thread = threading.Thread(target=upstream.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
self.addCleanup(thread.join, 5)
|
||||
target = f"ws://127.0.0.1:{upstream.socket.getsockname()[1]}/v1/realtime"
|
||||
with (
|
||||
patch.object(server, "S2S_PROXY_TARGET", target),
|
||||
patch.object(server, "S2S_INJECT_PROFILE", False),
|
||||
patch.object(server, "S2S_APIPILOT_TOOLS_URL", "http://catalog.test/tools"),
|
||||
patch.object(server, "S2S_LOGIN_BY_PHONE", "http://profile.test/login"),
|
||||
patch.object(server, "VOCERO_USER_PHONE_AUTH_URL", "http://profile.test/user"),
|
||||
patch.object(server, "_apipilot_fetch_tools", catalog),
|
||||
patch.object(server, "_login_by_phone", login),
|
||||
patch.object(server, "_fetch_user_profile_for_phone", profile),
|
||||
patch.object(server.httpx, "AsyncClient", side_effect=AssertionError("Unexpected HTTP request")),
|
||||
TestClient(server.app) as client,
|
||||
):
|
||||
with client.websocket_connect(
|
||||
"/v1/realtime?phoneNumber=%2B56000000000&episode_id=fixture-episode",
|
||||
) as socket:
|
||||
self.assertEqual(socket.receive_json(), {"type": "session.created"})
|
||||
socket.send_json({"type": "session.update", "session": {"instructions": "Local fixture"}})
|
||||
update = socket.receive_json()
|
||||
self.assertEqual(update["type"], "session.update")
|
||||
instructions = update["session"]["instructions"]
|
||||
for expected in (
|
||||
"Local fixture", server.APIPILOT_PASS1_LIST_MARKER, "name: get_caller_briefing",
|
||||
'phone = "+56000000000"', 'episode_id = "fixture-episode"',
|
||||
'email = "caller@example.test"',
|
||||
):
|
||||
self.assertIn(expected, instructions)
|
||||
# Configuration injection must preserve ordinary audio forwarding.
|
||||
audio = {"type": "input_audio_buffer.append", "audio": "AAA="}
|
||||
socket.send_json(audio)
|
||||
self.assertEqual(socket.receive_json(), audio)
|
||||
self.assertTrue(closed.wait(3), "Client disconnect must close the upstream WebSocket")
|
||||
login.assert_awaited_once_with("+56000000000")
|
||||
profile.assert_awaited_once_with("+56000000000", auth_token="fixture-token")
|
||||
catalog.assert_awaited_once_with(auth_header="Bearer fixture-token", demo_session=ANY, refresh=False)
|
||||
|
||||
def test_proxy_voice_frames_keepalive_and_client_disconnect(self):
|
||||
closed = threading.Event()
|
||||
received = []
|
||||
|
||||
Reference in New Issue
Block a user