feat: organize tools and enable qwen realtime calls

This commit is contained in:
Xin Wang
2026-08-14 00:15:00 +08:00
parent eb111a3890
commit 5be21f5ccc
71 changed files with 5771 additions and 2026 deletions
+76
View File
@@ -5,9 +5,11 @@ import uuid
from db.models import (
Assistant,
AssistantModelBinding,
AssistantToolBinding,
InterfaceDefinition,
KnowledgeBase,
ModelResource,
Tool,
)
from db.session import get_session
from fastapi import APIRouter, Depends, HTTPException, Query
@@ -51,6 +53,7 @@ def _definition_dict(row: InterfaceDefinition) -> dict:
"name": row.name,
"capability": row.capability,
"fields": (row.field_schema or {}).get("fields", []),
"features": (row.field_schema or {}).get("features", {}),
}
@@ -137,6 +140,78 @@ async def _clear_incompatible_references(
)
async def _ensure_realtime_prompt_tools_remain_supported(
session: AsyncSession,
resource: ModelResource,
definition: InterfaceDefinition,
) -> None:
"""Reject provider changes that would silently disable bound Prompt tools."""
if resource.capability != "Realtime":
return
features = {}
if definition.capability == "Realtime":
features = (
((definition.field_schema or {}).get("features") or {}).get(
"realtimePromptTools"
)
or {}
)
supported_external = set(features.get("externalTypes") or [])
supported_built_ins = set(features.get("builtIns") or [])
assistants = (
await session.execute(
select(Assistant)
.join(
AssistantModelBinding,
AssistantModelBinding.assistant_id == Assistant.id,
)
.where(
AssistantModelBinding.model_resource_id == resource.id,
AssistantModelBinding.capability == "Realtime",
Assistant.type == "prompt",
Assistant.runtime_mode == "realtime",
)
)
).scalars().all()
aliases = {
"end_conversation": "endConversation",
"update_state": "updateState",
"skip_turn": "skipTurn",
"request_human_handoff": "requestHumanHandoff",
}
for assistant in assistants:
requested_built_ins = {
aliases.get(str(name), str(name))
for name, config in (assistant.built_in_tools or {}).items()
if config is not None
}
if requested_built_ins - supported_built_ins:
raise HTTPException(
409,
f"模型资源被 Prompt Realtime 助手 {assistant.name} 使用,"
"新接口不支持其内建工具",
)
tool_types = set(
(
await session.execute(
select(Tool.type)
.join(
AssistantToolBinding,
AssistantToolBinding.tool_id == Tool.id,
)
.where(AssistantToolBinding.assistant_id == assistant.id)
)
).scalars().all()
)
if tool_types - supported_external:
raise HTTPException(
409,
f"模型资源被 Prompt Realtime 助手 {assistant.name} 使用,"
"新接口不支持其外部工具",
)
@router.get("/interface-definitions", response_model=list[InterfaceDefinitionOut])
async def list_interface_definitions(
capability: str | None = Query(default=None),
@@ -252,6 +327,7 @@ async def update_model_resource(
if not row:
raise HTTPException(404, "模型资源不存在")
definition, secrets = await _validate(session, body, row.secrets or {})
await _ensure_realtime_prompt_tools_remain_supported(session, row, definition)
await _clear_incompatible_references(session, row, definition.capability)
row.name = body.name
row.capability = definition.capability