66 lines
2.3 KiB
Python
66 lines
2.3 KiB
Python
"""Capability gates for Prompt tools in speech-to-speech runtimes."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections.abc import Mapping
|
||
|
||
from services.system_tools import RESERVED_TOOL_NAMES
|
||
|
||
|
||
QWEN_PROMPT_TOOL_FEATURES = {
|
||
"externalTypes": ["http", "mcp", "client"],
|
||
"builtIns": [
|
||
"endConversation",
|
||
"updateState",
|
||
"requestHumanHandoff",
|
||
],
|
||
}
|
||
|
||
|
||
def realtime_prompt_tool_features(interface_type: str) -> dict[str, list[str]]:
|
||
"""Return the server-trusted runtime capabilities for one provider."""
|
||
|
||
if interface_type == "qwen-audio-realtime":
|
||
return {
|
||
key: list(values) for key, values in QWEN_PROMPT_TOOL_FEATURES.items()
|
||
}
|
||
return {"externalTypes": [], "builtIns": []}
|
||
|
||
|
||
def validate_runtime_prompt_tools(
|
||
*,
|
||
interface_type: str,
|
||
external_types: set[str],
|
||
built_in_tools: Mapping[str, object] | None,
|
||
external_function_names: set[str] | None = None,
|
||
) -> None:
|
||
"""Reject stale or inline runtime configurations before opening a socket."""
|
||
|
||
features = realtime_prompt_tool_features(interface_type)
|
||
unsupported_external = external_types - set(features["externalTypes"])
|
||
reserved_external = set(external_function_names or set()) & RESERVED_TOOL_NAMES
|
||
aliases = {
|
||
"end_conversation": "endConversation",
|
||
"update_state": "updateState",
|
||
"skip_turn": "skipTurn",
|
||
"request_human_handoff": "requestHumanHandoff",
|
||
}
|
||
requested_built_ins = {
|
||
aliases.get(str(name), str(name))
|
||
for name, config in (built_in_tools or {}).items()
|
||
if config is not None
|
||
}
|
||
unsupported_built_ins = requested_built_ins - set(features["builtIns"])
|
||
if unsupported_external or unsupported_built_ins or reserved_external:
|
||
details = []
|
||
if unsupported_external:
|
||
details.append("外部工具:" + ",".join(sorted(unsupported_external)))
|
||
if unsupported_built_ins:
|
||
details.append("内建工具:" + ",".join(sorted(unsupported_built_ins)))
|
||
if reserved_external:
|
||
details.append("外部工具使用平台保留名:" + ",".join(sorted(reserved_external)))
|
||
raise ValueError(
|
||
f"Realtime 接口 {interface_type or 'unknown'} 不支持 "
|
||
+ ";".join(details)
|
||
)
|