fix(proxy): pass the ApiPilot catalog with the correct argument

This commit is contained in:
2026-10-06 17:44:43 -03:00
parent c375581077
commit 3d42df5749
2 changed files with 61 additions and 2 deletions
+60 -1
View File
@@ -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 = []