Add reusable tools and assistant bindings
- Introduce a new `Tool` model and `AssistantToolBinding` for managing reusable tools within the application. - Implement CRUD operations for tools in the new `tools` route, allowing for the creation, retrieval, updating, and deletion of tools. - Update the `Assistant` model to include a list of tool IDs, enabling assistants to utilize these tools. - Enhance the backend routes to synchronize tool bindings with assistants, ensuring proper management of tool associations. - Add frontend components for tool management, including a tool picker in the assistant configuration, improving user experience in tool selection. - Create a mobile call page to facilitate video calls, integrating camera and microphone selection for enhanced communication capabilities. - Update API definitions to include tool-related types and operations, ensuring consistency across the application. - Add a migration script to create the necessary database tables for tools and bindings, supporting the new functionality.
This commit is contained in:
@@ -7,14 +7,18 @@ JSON 用 camelCase(modelId/interfaceType/apiUrl/apiKey),Python 内部用 snake_c
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Literal
|
||||
from typing import Annotated, Any, Literal, Union
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
RuntimeMode = Literal["pipeline", "realtime"]
|
||||
ModelType = Literal["LLM", "ASR", "TTS", "Realtime", "Embedding", "Agent"]
|
||||
AssistantType = Literal["prompt", "workflow", "dify", "fastgpt", "opencode"]
|
||||
ToolType = Literal["end_call", "http"]
|
||||
ToolStatus = Literal["active", "archived", "draft"]
|
||||
ToolParameterType = Literal["string", "number", "integer", "boolean", "object", "array"]
|
||||
ToolParameterLocation = Literal["path", "query", "body", "header"]
|
||||
|
||||
# 外部应用类型:其 config.apiKey 是该助手私有密钥,读时打码 / 写时哨兵
|
||||
EXTERNAL_TYPES = {"dify", "fastgpt", "opencode"}
|
||||
@@ -57,6 +61,7 @@ class AssistantUpsert(CamelModel):
|
||||
|
||||
model_resource_ids: dict[ModelType, str] = Field(default_factory=dict)
|
||||
knowledge_base_id: str | None = None
|
||||
tool_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
# 瘦类型专属(真列);按 type 取用,无关字段写入时清零
|
||||
prompt: str = ""
|
||||
@@ -74,6 +79,8 @@ class AssistantUpsert(CamelModel):
|
||||
setattr(self, field, "")
|
||||
if "graph" not in allowed:
|
||||
self.graph = {}
|
||||
if self.type != "prompt":
|
||||
self.tool_ids = []
|
||||
# 外部托管大脑只能 cascade,拦住不兼容的 realtime
|
||||
if self.runtime_mode == "realtime" and self.type not in REALTIME_CAPABLE_TYPES:
|
||||
raise ValueError(f"类型 {self.type} 不支持 realtime 运行模式")
|
||||
@@ -85,6 +92,69 @@ class AssistantOut(AssistantUpsert):
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
# ---------- 可复用工具 ----------
|
||||
class ToolParameter(CamelModel):
|
||||
name: str
|
||||
type: ToolParameterType = "string"
|
||||
location: ToolParameterLocation = "body"
|
||||
description: str = ""
|
||||
required: bool = True
|
||||
|
||||
|
||||
class EndCallToolConfig(CamelModel):
|
||||
message_type: Literal["none", "custom"] = "none"
|
||||
custom_message: str = ""
|
||||
capture_reason: bool = True
|
||||
|
||||
|
||||
class HttpToolConfig(CamelModel):
|
||||
method: Literal["GET", "POST", "PUT", "PATCH", "DELETE"] = "GET"
|
||||
url: str
|
||||
timeout_seconds: int = Field(default=15, ge=1, le=120)
|
||||
headers: dict[str, str] = Field(default_factory=dict)
|
||||
parameters: list[ToolParameter] = Field(default_factory=list)
|
||||
body: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
@field_validator("url")
|
||||
@classmethod
|
||||
def validate_url(cls, value: str) -> str:
|
||||
if not value.startswith(("http://", "https://")):
|
||||
raise ValueError("HTTP 工具 URL 必须使用 http:// 或 https://")
|
||||
return value
|
||||
|
||||
|
||||
class EndCallToolDefinition(CamelModel):
|
||||
schema_version: int = 1
|
||||
type: Literal["end_call"] = "end_call"
|
||||
config: EndCallToolConfig = Field(default_factory=EndCallToolConfig)
|
||||
|
||||
|
||||
class HttpToolDefinition(CamelModel):
|
||||
schema_version: int = 1
|
||||
type: Literal["http"] = "http"
|
||||
config: HttpToolConfig
|
||||
|
||||
|
||||
ToolDefinition = Annotated[
|
||||
Union[EndCallToolDefinition, HttpToolDefinition], Field(discriminator="type")
|
||||
]
|
||||
|
||||
|
||||
class ToolUpsert(CamelModel):
|
||||
name: str = Field(min_length=1, max_length=128)
|
||||
function_name: str = Field(pattern=r"^[a-z][a-z0-9_]{0,63}$")
|
||||
description: str = Field(default="", max_length=2048)
|
||||
definition: ToolDefinition
|
||||
secrets: dict[str, Any] = Field(default_factory=dict)
|
||||
status: ToolStatus = "active"
|
||||
|
||||
|
||||
class ToolOut(ToolUpsert):
|
||||
id: str
|
||||
type: ToolType
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
# ---------- 知识库 ----------
|
||||
class KnowledgeBaseUpsert(CamelModel):
|
||||
name: str
|
||||
|
||||
Reference in New Issue
Block a user