Add client service metadata sanitization and debug source check
This commit is contained in:
@@ -71,6 +71,32 @@ class Session:
|
||||
"configVersionId",
|
||||
"config_version_id",
|
||||
}
|
||||
_CLIENT_SERVICE_OVERRIDES = {
|
||||
"llm": {
|
||||
"provider",
|
||||
"model",
|
||||
"apiKey",
|
||||
"baseUrl",
|
||||
},
|
||||
"asr": {
|
||||
"provider",
|
||||
"model",
|
||||
"apiKey",
|
||||
"baseUrl",
|
||||
"interimIntervalMs",
|
||||
"minAudioMs",
|
||||
},
|
||||
"tts": {
|
||||
"enabled",
|
||||
"provider",
|
||||
"model",
|
||||
"apiKey",
|
||||
"baseUrl",
|
||||
"voice",
|
||||
"speed",
|
||||
"mode",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -853,13 +879,52 @@ class Session:
|
||||
def _sanitize_client_metadata(self, metadata: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Apply client metadata whitelist and remove forbidden secrets."""
|
||||
sanitized = self._sanitize_untrusted_runtime_metadata(metadata)
|
||||
if isinstance(metadata.get("services"), dict):
|
||||
services = metadata.get("services")
|
||||
if isinstance(services, dict):
|
||||
if self._is_debug_metadata_source(metadata):
|
||||
sanitized_services = self._sanitize_client_services(services)
|
||||
if sanitized_services:
|
||||
sanitized["services"] = sanitized_services
|
||||
else:
|
||||
logger.warning(
|
||||
"Session {} provided metadata.services from client; client-side service config is ignored",
|
||||
self.id,
|
||||
)
|
||||
return sanitized
|
||||
|
||||
@staticmethod
|
||||
def _is_debug_metadata_source(metadata: Dict[str, Any]) -> bool:
|
||||
source = str(metadata.get("source") or "").strip().lower()
|
||||
if source == "debug":
|
||||
return True
|
||||
|
||||
history = metadata.get("history")
|
||||
if isinstance(history, dict):
|
||||
history_source = str(history.get("source") or "").strip().lower()
|
||||
if history_source == "debug":
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def _sanitize_client_services(cls, services: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if not isinstance(services, dict):
|
||||
return {}
|
||||
|
||||
sanitized_services: Dict[str, Any] = {}
|
||||
for service_name, allowed_keys in cls._CLIENT_SERVICE_OVERRIDES.items():
|
||||
payload = services.get(service_name)
|
||||
if not isinstance(payload, dict):
|
||||
continue
|
||||
|
||||
sanitized_payload = {
|
||||
key: payload[key]
|
||||
for key in allowed_keys
|
||||
if key in payload
|
||||
}
|
||||
if sanitized_payload:
|
||||
sanitized_services[service_name] = sanitized_payload
|
||||
return sanitized_services
|
||||
|
||||
def _build_config_resolved(self, metadata: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Build public resolved config payload (secrets removed)."""
|
||||
system_prompt = str(metadata.get("systemPrompt") or self.pipeline.conversation.system_prompt or "")
|
||||
|
||||
@@ -2296,10 +2296,10 @@ export const DebugDrawer: React.FC<{
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) return;
|
||||
// If core TTS-related settings changed while drawer stays open,
|
||||
// If core runtime settings changed while drawer stays open,
|
||||
// reset the active WS session so the next launch uses new metadata.
|
||||
closeWs();
|
||||
}, [isOpen, assistant.id, assistant.voice, assistant.speed]);
|
||||
}, [isOpen, assistant.id, assistant.voice, assistant.speed, assistant.asrModelId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!textTtsEnabled) {
|
||||
|
||||
Reference in New Issue
Block a user