Enhance WebSocket session configuration by introducing an optional config.resolved event, which provides a public snapshot of the session's configuration. Update the API reference documentation to clarify the conditions under which this event is emitted and the details it includes. Modify session management to respect the new setting for emitting configuration details, ensuring sensitive information remains secure. Update tests to validate the new behavior and ensure compliance with the updated configuration schema.

This commit is contained in:
Xin Wang
2026-03-01 23:08:44 +08:00
parent 2418df80e5
commit 3643431565
6 changed files with 165 additions and 58 deletions

View File

@@ -143,7 +143,9 @@ async def test_handle_session_start_requires_assistant_id_and_closes_transport()
@pytest.mark.asyncio
async def test_handle_session_start_applies_whitelisted_overrides_and_ignores_workflow():
async def test_handle_session_start_applies_whitelisted_overrides_and_ignores_workflow(monkeypatch):
monkeypatch.setattr("core.session.settings.ws_emit_config_resolved", False)
session = Session.__new__(Session)
session.id = "sess_start_ok"
session.ws_state = WsSessionState.WAIT_START
@@ -175,7 +177,7 @@ async def test_handle_session_start_applies_whitelisted_overrides_and_ignores_wo
return {
"output": {"mode": "text"},
"services": {"llm": {"provider": "openai", "model": "gpt-4o-mini"}},
"tools": {"allowlist": []},
"tools": {"allowlist": ["calculator"]},
}
session.transport = _Transport()
@@ -232,7 +234,94 @@ async def test_handle_session_start_applies_whitelisted_overrides_and_ignores_wo
assert session.pipeline.applied["output"]["mode"] == "text"
assert session.pipeline.applied["tools"] == [{"name": "calculator"}]
assert not any(str(item.get("type", "")).startswith("workflow.") for item in events)
assert not any(item.get("type") == "config.resolved" for item in events)
@pytest.mark.asyncio
async def test_handle_session_start_emits_config_resolved_when_enabled(monkeypatch):
monkeypatch.setattr("core.session.settings.ws_emit_config_resolved", True)
session = Session.__new__(Session)
session.id = "sess_start_emit_config"
session.ws_state = WsSessionState.WAIT_START
session.state = "created"
session._assistant_id = "assistant_demo"
session.current_track_id = Session.TRACK_CONTROL
session._pipeline_started = False
class _Transport:
async def close(self):
return None
class _Pipeline:
def __init__(self):
self.started = False
self.applied = {}
self.conversation = type("Conversation", (), {"system_prompt": ""})()
async def start(self):
self.started = True
async def emit_initial_greeting(self):
return None
def apply_runtime_overrides(self, metadata):
self.applied = dict(metadata)
def resolved_runtime_config(self):
return {
"output": {"mode": "text"},
"services": {"llm": {"provider": "openai", "model": "gpt-4o-mini"}},
"tools": {"allowlist": ["calculator"]},
}
session.transport = _Transport()
session.pipeline = _Pipeline()
events = []
async def _start_history_bridge(_metadata):
return None
async def _load_server_runtime_metadata(_assistant_id):
return (
{
"assistantId": "assistant_demo",
"configVersionId": "cfg_1",
"systemPrompt": "Base prompt",
"greeting": "Base greeting",
"output": {"mode": "audio"},
},
None,
)
async def _send_event(event):
events.append(event)
async def _send_error(sender, message, code, **kwargs):
raise AssertionError(f"Unexpected error: sender={sender} code={code} message={message} kwargs={kwargs}")
session._start_history_bridge = _start_history_bridge
session._load_server_runtime_metadata = _load_server_runtime_metadata
session._send_event = _send_event
session._send_error = _send_error
await session._handle_session_start(
SessionStartMessage(
type="session.start",
metadata={
"channel": "web_debug",
"overrides": {
"output": {"mode": "text"},
},
},
)
)
config_event = next(item for item in events if item.get("type") == "config.resolved")
assert config_event["config"]["appId"] == "assistant_demo"
assert "appId" not in config_event["config"]
assert "configVersionId" not in config_event["config"]
assert "services" not in config_event["config"]
assert config_event["config"]["channel"] == "web_debug"
assert config_event["config"]["output"]["mode"] == "text"
assert config_event["config"]["tools"]["enabled"] is True
assert config_event["config"]["tools"]["count"] == 1