Add dynamic variable support to Assistant model and related components

- Introduce dynamic variable definitions in AssistantConfig and Assistant models, allowing for flexible prompt customization.
- Implement validation for dynamic variable names and types in the schema.
- Update backend services and routes to handle dynamic variables in assistant configurations and runtime processing.
- Enhance frontend components to support dynamic variable definitions, including a new editor for managing variables.
- Add tests to ensure proper functionality and validation of dynamic variables in various scenarios.
This commit is contained in:
Xin Wang
2026-07-12 23:42:56 +08:00
parent 7c9a18c806
commit deaf3d7730
21 changed files with 1396 additions and 12 deletions

View File

@@ -8,6 +8,7 @@ JSON 用 camelCase(modelId/interfaceType/apiUrl/apiKey),Python 内部用 snake_c
from __future__ import annotations
from datetime import datetime
import re
from typing import Annotated, Any, Literal, Union
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
@@ -22,6 +23,7 @@ ToolType = Literal["end_call", "http"]
ToolStatus = Literal["active", "archived", "draft"]
ToolParameterType = Literal["string", "number", "integer", "boolean", "object", "array"]
ToolParameterLocation = Literal["path", "query", "body", "header"]
DynamicVariableType = Literal["string", "number", "boolean"]
# 外部应用类型:其 config.apiKey 是该助手私有密钥,读时打码 / 写时哨兵
EXTERNAL_TYPES = {"dify", "fastgpt", "opencode"}
@@ -106,12 +108,28 @@ class AssistantUpsert(CamelModel):
# 瘦类型专属(真列);按 type 取用,无关字段写入时清零
prompt: str = ""
dynamic_variable_definitions: dict[str, "DynamicVariableDefinition"] = Field(
default_factory=dict
)
api_url: str = ""
api_key: str = "" # 写时:占位符/空 → 保留旧(哨兵)
app_id: str = ""
# workflow 专属:图
graph: dict[str, Any] = Field(default_factory=dict)
@field_validator("dynamic_variable_definitions")
@classmethod
def validate_dynamic_variable_names(cls, value):
if len(value) > 50:
raise ValueError("动态变量最多允许 50 个")
for name in value:
if (
not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]{0,63}", name)
or name.startswith(("system__", "secret__"))
):
raise ValueError(f"动态变量名称不合法: {name}")
return value
@model_validator(mode="after")
def _strip_irrelevant_fields(self):
allowed = ALLOWED_FIELDS[self.type]
@@ -122,6 +140,7 @@ class AssistantUpsert(CamelModel):
self.graph = {}
if self.type != "prompt":
self.tool_ids = []
self.dynamic_variable_definitions = {}
# 外部托管大脑只能 cascade,拦住不兼容的 realtime
if self.runtime_mode == "realtime" and self.type not in REALTIME_CAPABLE_TYPES:
raise ValueError(f"类型 {self.type} 不支持 realtime 运行模式")
@@ -133,6 +152,29 @@ class AssistantOut(AssistantUpsert):
updated_at: str | None = None
class DynamicVariableDefinition(CamelModel):
type: DynamicVariableType = "string"
required: bool = False
default: str | int | float | bool | None = None
@model_validator(mode="after")
def validate_default_type(self):
if self.default is None:
return self
valid = (
(self.type == "string" and isinstance(self.default, str))
or (
self.type == "number"
and isinstance(self.default, (int, float))
and not isinstance(self.default, bool)
)
or (self.type == "boolean" and isinstance(self.default, bool))
)
if not valid:
raise ValueError(f"默认值类型应为 {self.type}")
return self
# ---------- 可复用工具 ----------
class ToolParameter(CamelModel):
name: str
@@ -155,6 +197,7 @@ class HttpToolConfig(CamelModel):
headers: dict[str, str] = Field(default_factory=dict)
parameters: list[ToolParameter] = Field(default_factory=list)
body: dict[str, Any] = Field(default_factory=dict)
dynamic_variable_assignments: dict[str, str] = Field(default_factory=dict)
@field_validator("url")
@classmethod