feat: add support for Graph Tools in AIAgent model and related services
This commit is contained in:
@@ -73,16 +73,23 @@ func (c *toolCatalog) parseSkillAllowedToolCodes(skill *models.SkillDefinition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *toolCatalog) parseAgentAllowedToolCodes(aiAgent *models.AIAgent) []string {
|
func (c *toolCatalog) parseAgentAllowedToolCodes(aiAgent *models.AIAgent) []string {
|
||||||
if aiAgent == nil || strings.TrimSpace(aiAgent.AllowedMCPTools) == "" {
|
if aiAgent == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
items, err := toolx.ParseAgentMCPToolsJSON(aiAgent.AllowedMCPTools)
|
ret := make([]string, 0)
|
||||||
if err != nil {
|
if raw := strings.TrimSpace(aiAgent.AllowedMCPTools); raw != "" {
|
||||||
return nil
|
items, err := toolx.ParseAgentMCPToolsJSON(raw)
|
||||||
|
if err == nil {
|
||||||
|
for _, item := range items {
|
||||||
|
ret = append(ret, item.ToolCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret := make([]string, 0, len(items))
|
if raw := strings.TrimSpace(aiAgent.AllowedGraphTools); raw != "" {
|
||||||
for _, item := range items {
|
var graphTools []string
|
||||||
ret = append(ret, item.ToolCode)
|
if err := json.Unmarshal([]byte(raw), &graphTools); err == nil {
|
||||||
|
ret = append(ret, graphTools...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return toolx.NormalizeToolCodes(ret)
|
return toolx.NormalizeToolCodes(ret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ func buildAIAgentResponse(item *models.AIAgent) response.AIAgentResponse {
|
|||||||
Skills: make([]response.AIAgentSkillResponse, 0),
|
Skills: make([]response.AIAgentSkillResponse, 0),
|
||||||
Teams: make([]response.AIAgentTeamResponse, 0),
|
Teams: make([]response.AIAgentTeamResponse, 0),
|
||||||
DirectTools: make([]response.AIAgentMCPToolResponse, 0),
|
DirectTools: make([]response.AIAgentMCPToolResponse, 0),
|
||||||
|
GraphTools: make([]string, 0),
|
||||||
SortNo: item.SortNo,
|
SortNo: item.SortNo,
|
||||||
Remark: item.Remark,
|
Remark: item.Remark,
|
||||||
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"),
|
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||||
@@ -175,6 +176,10 @@ func buildAIAgentResponse(item *models.AIAgent) response.AIAgentResponse {
|
|||||||
if toolx.IsAutoInjectedToolCode(toolCode) {
|
if toolx.IsAutoInjectedToolCode(toolCode) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if toolx.IsAgentDirectGraphToolCode(toolCode) {
|
||||||
|
ret.GraphTools = appendGraphToolCodeIfMissing(ret.GraphTools, toolCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
serverCode := strings.TrimSpace(tool.ServerCode)
|
serverCode := strings.TrimSpace(tool.ServerCode)
|
||||||
toolName := strings.TrimSpace(tool.ToolName)
|
toolName := strings.TrimSpace(tool.ToolName)
|
||||||
if registeredServerCode, registeredToolName, ok := toolx.GetRegisteredToolIdentity(toolCode); ok {
|
if registeredServerCode, registeredToolName, ok := toolx.GetRegisteredToolIdentity(toolCode); ok {
|
||||||
@@ -207,5 +212,30 @@ func buildAIAgentResponse(item *models.AIAgent) response.AIAgentResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if raw := strings.TrimSpace(item.AllowedGraphTools); raw != "" {
|
||||||
|
var graphTools []string
|
||||||
|
if err := json.Unmarshal([]byte(raw), &graphTools); err == nil {
|
||||||
|
for _, toolCode := range graphTools {
|
||||||
|
toolCode = toolx.NormalizeToolCodeAlias(strings.TrimSpace(toolCode))
|
||||||
|
if !toolx.IsAgentDirectGraphToolCode(toolCode) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret.GraphTools = appendGraphToolCodeIfMissing(ret.GraphTools, toolCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendGraphToolCodeIfMissing(items []string, toolCode string) []string {
|
||||||
|
toolCode = strings.TrimSpace(toolCode)
|
||||||
|
if toolCode == "" {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
for _, item := range items {
|
||||||
|
if strings.TrimSpace(item) == toolCode {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(items, toolCode)
|
||||||
|
}
|
||||||
|
|||||||
@@ -514,6 +514,7 @@ type AIAgent struct {
|
|||||||
KnowledgeIDs string `gorm:"type:varchar(500);not null;default:''"` // KnowledgeIDs 为绑定的知识库ID列表,按顺序表示优先级。
|
KnowledgeIDs string `gorm:"type:varchar(500);not null;default:''"` // KnowledgeIDs 为绑定的知识库ID列表,按顺序表示优先级。
|
||||||
SkillIDs string `gorm:"type:varchar(500);not null;default:''"` // SkillIDs 为绑定的技能ID列表,按顺序表示允许路由的范围。
|
SkillIDs string `gorm:"type:varchar(500);not null;default:''"` // SkillIDs 为绑定的技能ID列表,按顺序表示允许路由的范围。
|
||||||
AllowedMCPTools string `gorm:"type:text"` // AllowedMCPTools 为允许 direct tool 路由的 MCP 工具白名单配置JSON。
|
AllowedMCPTools string `gorm:"type:text"` // AllowedMCPTools 为允许 direct tool 路由的 MCP 工具白名单配置JSON。
|
||||||
|
AllowedGraphTools string `gorm:"type:text"` // AllowedGraphTools 为允许 Graph Tool 的白名单配置JSON。
|
||||||
SortNo int `gorm:"type:int;not null;default:0;index"` // SortNo 为后台展示排序号。
|
SortNo int `gorm:"type:int;not null;default:0;index"` // SortNo 为后台展示排序号。
|
||||||
Remark string `gorm:"type:text"` // Remark 为备注。
|
Remark string `gorm:"type:text"` // Remark 为备注。
|
||||||
AuditFields
|
AuditFields
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ type CreateAIAgentRequest struct {
|
|||||||
KnowledgeIDs []int64 `json:"knowledgeIds"`
|
KnowledgeIDs []int64 `json:"knowledgeIds"`
|
||||||
SkillIDs []int64 `json:"skillIds"`
|
SkillIDs []int64 `json:"skillIds"`
|
||||||
DirectTools []AIAgentMCPToolRequest `json:"directTools"`
|
DirectTools []AIAgentMCPToolRequest `json:"directTools"`
|
||||||
|
GraphTools []string `json:"graphTools"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ type AIAgentResponse struct {
|
|||||||
SkillIDs []int64 `json:"skillIds"`
|
SkillIDs []int64 `json:"skillIds"`
|
||||||
Skills []AIAgentSkillResponse `json:"skills"`
|
Skills []AIAgentSkillResponse `json:"skills"`
|
||||||
DirectTools []AIAgentMCPToolResponse `json:"directTools"`
|
DirectTools []AIAgentMCPToolResponse `json:"directTools"`
|
||||||
|
GraphTools []string `json:"graphTools"`
|
||||||
SortNo int `json:"sortNo"`
|
SortNo int `json:"sortNo"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
CreatedAt string `json:"createdAt"`
|
CreatedAt string `json:"createdAt"`
|
||||||
|
|||||||
@@ -281,6 +281,12 @@ func IsAgentDirectToolCode(toolCode string) bool {
|
|||||||
return ok && spec.DirectAccess
|
return ok && spec.DirectAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsAgentDirectGraphToolCode(toolCode string) bool {
|
||||||
|
toolCode = NormalizeToolCodeAlias(strings.TrimSpace(toolCode))
|
||||||
|
spec, ok := GetRegisteredToolSpec(toolCode)
|
||||||
|
return ok && spec.DirectAccess && spec.SourceType == enums.ToolSourceTypeGraph
|
||||||
|
}
|
||||||
|
|
||||||
func NormalizeToolCodeAlias(toolCode string) string {
|
func NormalizeToolCodeAlias(toolCode string) string {
|
||||||
toolCode = strings.TrimSpace(toolCode)
|
toolCode = strings.TrimSpace(toolCode)
|
||||||
if canonical, ok := toolAliasToCanonical[toolCode]; ok {
|
if canonical, ok := toolAliasToCanonical[toolCode]; ok {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ func (s *aIAgentService) UpdateAIAgent(req request.UpdateAIAgentRequest, operato
|
|||||||
"knowledge_ids": item.KnowledgeIDs,
|
"knowledge_ids": item.KnowledgeIDs,
|
||||||
"skill_ids": item.SkillIDs,
|
"skill_ids": item.SkillIDs,
|
||||||
"allowed_mcp_tools": item.AllowedMCPTools,
|
"allowed_mcp_tools": item.AllowedMCPTools,
|
||||||
|
"allowed_graph_tools": item.AllowedGraphTools,
|
||||||
"remark": item.Remark,
|
"remark": item.Remark,
|
||||||
"update_user_id": operator.UserID,
|
"update_user_id": operator.UserID,
|
||||||
"update_user_name": operator.Username,
|
"update_user_name": operator.Username,
|
||||||
@@ -179,6 +180,10 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
graphTools, err := s.normalizeGraphTools(req.GraphTools)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
directToolsJSON := ""
|
directToolsJSON := ""
|
||||||
if len(directTools) > 0 {
|
if len(directTools) > 0 {
|
||||||
buf, marshalErr := json.Marshal(directTools)
|
buf, marshalErr := json.Marshal(directTools)
|
||||||
@@ -187,6 +192,14 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
|
|||||||
}
|
}
|
||||||
directToolsJSON = string(buf)
|
directToolsJSON = string(buf)
|
||||||
}
|
}
|
||||||
|
graphToolsJSON := ""
|
||||||
|
if len(graphTools) > 0 {
|
||||||
|
buf, marshalErr := json.Marshal(graphTools)
|
||||||
|
if marshalErr != nil {
|
||||||
|
return nil, errorsx.InvalidParam("Graph Tools 配置格式不合法")
|
||||||
|
}
|
||||||
|
graphToolsJSON = string(buf)
|
||||||
|
}
|
||||||
return &models.AIAgent{
|
return &models.AIAgent{
|
||||||
Name: name,
|
Name: name,
|
||||||
Description: strings.TrimSpace(req.Description),
|
Description: strings.TrimSpace(req.Description),
|
||||||
@@ -201,6 +214,7 @@ func (s *aIAgentService) buildAIAgentModel(id int64, req request.CreateAIAgentRe
|
|||||||
KnowledgeIDs: utils.JoinInt64s(knowledgeIDs),
|
KnowledgeIDs: utils.JoinInt64s(knowledgeIDs),
|
||||||
SkillIDs: utils.JoinInt64s(skillIDs),
|
SkillIDs: utils.JoinInt64s(skillIDs),
|
||||||
AllowedMCPTools: directToolsJSON,
|
AllowedMCPTools: directToolsJSON,
|
||||||
|
AllowedGraphTools: graphToolsJSON,
|
||||||
Remark: strings.TrimSpace(req.Remark),
|
Remark: strings.TrimSpace(req.Remark),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -289,6 +303,9 @@ func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequ
|
|||||||
if toolx.IsAutoInjectedToolCode(strings.TrimSpace(normalized.ToolCode)) {
|
if toolx.IsAutoInjectedToolCode(strings.TrimSpace(normalized.ToolCode)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if toolx.ResolveToolSourceType(normalized.ToolCode) != enums.ToolSourceTypeMCP {
|
||||||
|
return nil, errorsx.InvalidParam("Direct Tools 仅允许配置 MCP 工具")
|
||||||
|
}
|
||||||
if err := ToolCatalogService.ValidateToolCode(normalized.ToolCode); err != nil {
|
if err := ToolCatalogService.ValidateToolCode(normalized.ToolCode); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -302,6 +319,29 @@ func (s *aIAgentService) normalizeDirectTools(input []request.AIAgentMCPToolRequ
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *aIAgentService) normalizeGraphTools(input []string) ([]string, error) {
|
||||||
|
if len(input) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
ret := make([]string, 0, len(input))
|
||||||
|
seen := make(map[string]struct{})
|
||||||
|
for _, item := range input {
|
||||||
|
toolCode := toolx.NormalizeToolCodeAlias(strings.TrimSpace(item))
|
||||||
|
if toolCode == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !toolx.IsAgentDirectGraphToolCode(toolCode) {
|
||||||
|
return nil, errorsx.InvalidParam("Graph Tools 仅允许配置 Graph Tool")
|
||||||
|
}
|
||||||
|
if _, exists := seen[toolCode]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[toolCode] = struct{}{}
|
||||||
|
ret = append(ret, toolCode)
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *aIAgentService) UpdateSort(ids []int64) error {
|
func (s *aIAgentService) UpdateSort(ids []int64) error {
|
||||||
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
|
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ type DirectToolOption = {
|
|||||||
groupLabel: string;
|
groupLabel: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type GraphToolOption = {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
type EditDialogProps = {
|
type EditDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
saving: boolean;
|
saving: boolean;
|
||||||
@@ -150,6 +155,7 @@ function buildPayload(
|
|||||||
teamIds: number[],
|
teamIds: number[],
|
||||||
skillIds: number[],
|
skillIds: number[],
|
||||||
directTools: CreateAIAgentPayload["directTools"],
|
directTools: CreateAIAgentPayload["directTools"],
|
||||||
|
graphTools: CreateAIAgentPayload["graphTools"],
|
||||||
): CreateAIAgentPayload {
|
): CreateAIAgentPayload {
|
||||||
return {
|
return {
|
||||||
name: form.name.trim(),
|
name: form.name.trim(),
|
||||||
@@ -165,6 +171,7 @@ function buildPayload(
|
|||||||
knowledgeIds,
|
knowledgeIds,
|
||||||
skillIds,
|
skillIds,
|
||||||
directTools,
|
directTools,
|
||||||
|
graphTools,
|
||||||
remark: form.remark.trim(),
|
remark: form.remark.trim(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -226,14 +233,19 @@ function EditDialogBody({
|
|||||||
const [skillToAdd, setSkillToAdd] = useState("");
|
const [skillToAdd, setSkillToAdd] = useState("");
|
||||||
const [directToolGroupToAdd, setDirectToolGroupToAdd] = useState("");
|
const [directToolGroupToAdd, setDirectToolGroupToAdd] = useState("");
|
||||||
const [directToolToAdd, setDirectToolToAdd] = useState("");
|
const [directToolToAdd, setDirectToolToAdd] = useState("");
|
||||||
|
const [graphToolToAdd, setGraphToolToAdd] = useState("");
|
||||||
const [aiConfigs, setAIConfigs] = useState<AIConfig[]>([]);
|
const [aiConfigs, setAIConfigs] = useState<AIConfig[]>([]);
|
||||||
const [knowledgeBases, setKnowledgeBases] = useState<KnowledgeBase[]>([]);
|
const [knowledgeBases, setKnowledgeBases] = useState<KnowledgeBase[]>([]);
|
||||||
const [agentTeams, setAgentTeams] = useState<AdminAgentTeam[]>([]);
|
const [agentTeams, setAgentTeams] = useState<AdminAgentTeam[]>([]);
|
||||||
const [skills, setSkills] = useState<SkillDefinition[]>([]);
|
const [skills, setSkills] = useState<SkillDefinition[]>([]);
|
||||||
const [directTools, setDirectTools] = useState<DirectToolItem[]>([]);
|
const [directTools, setDirectTools] = useState<DirectToolItem[]>([]);
|
||||||
|
const [graphTools, setGraphTools] = useState<string[]>([]);
|
||||||
const [directToolOptions, setDirectToolOptions] = useState<DirectToolOption[]>(
|
const [directToolOptions, setDirectToolOptions] = useState<DirectToolOption[]>(
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
const [graphToolOptions, setGraphToolOptions] = useState<GraphToolOption[]>(
|
||||||
|
[],
|
||||||
|
);
|
||||||
const [toolCatalog, setToolCatalog] = useState<MCPToolCatalogItem[]>([]);
|
const [toolCatalog, setToolCatalog] = useState<MCPToolCatalogItem[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -244,11 +256,13 @@ function EditDialogBody({
|
|||||||
setSelectedTeamIds([]);
|
setSelectedTeamIds([]);
|
||||||
setSelectedSkillIds([]);
|
setSelectedSkillIds([]);
|
||||||
setDirectTools([]);
|
setDirectTools([]);
|
||||||
|
setGraphTools([]);
|
||||||
setKnowledgeToAdd("");
|
setKnowledgeToAdd("");
|
||||||
setTeamToAdd("");
|
setTeamToAdd("");
|
||||||
setSkillToAdd("");
|
setSkillToAdd("");
|
||||||
setDirectToolGroupToAdd("");
|
setDirectToolGroupToAdd("");
|
||||||
setDirectToolToAdd("");
|
setDirectToolToAdd("");
|
||||||
|
setGraphToolToAdd("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -259,11 +273,13 @@ function EditDialogBody({
|
|||||||
setSelectedTeamIds((data.teams ?? []).map((team) => team.id));
|
setSelectedTeamIds((data.teams ?? []).map((team) => team.id));
|
||||||
setSelectedSkillIds(data.skillIds ?? []);
|
setSelectedSkillIds(data.skillIds ?? []);
|
||||||
setDirectTools(data.directTools ?? []);
|
setDirectTools(data.directTools ?? []);
|
||||||
|
setGraphTools(data.graphTools ?? []);
|
||||||
setKnowledgeToAdd("");
|
setKnowledgeToAdd("");
|
||||||
setTeamToAdd("");
|
setTeamToAdd("");
|
||||||
setSkillToAdd("");
|
setSkillToAdd("");
|
||||||
setDirectToolGroupToAdd("");
|
setDirectToolGroupToAdd("");
|
||||||
setDirectToolToAdd("");
|
setDirectToolToAdd("");
|
||||||
|
setGraphToolToAdd("");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(
|
toast.error(
|
||||||
error instanceof Error ? error.message : "加载 AI Agent 详情失败",
|
error instanceof Error ? error.message : "加载 AI Agent 详情失败",
|
||||||
@@ -338,7 +354,7 @@ function EditDialogBody({
|
|||||||
setToolCatalog(catalog);
|
setToolCatalog(catalog);
|
||||||
setDirectToolOptions(
|
setDirectToolOptions(
|
||||||
catalog
|
catalog
|
||||||
.filter((tool) => !tool.autoInjected)
|
.filter((tool) => !tool.autoInjected && tool.sourceType === "mcp")
|
||||||
.map((tool) => ({
|
.map((tool) => ({
|
||||||
value: tool.toolCode,
|
value: tool.toolCode,
|
||||||
label: `${tool.title || tool.toolName} · ${tool.toolCode}`,
|
label: `${tool.title || tool.toolName} · ${tool.toolCode}`,
|
||||||
@@ -358,6 +374,14 @@ function EditDialogBody({
|
|||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
setGraphToolOptions(
|
||||||
|
catalog
|
||||||
|
.filter((tool) => tool.sourceType === "graph")
|
||||||
|
.map((tool) => ({
|
||||||
|
value: tool.toolCode,
|
||||||
|
label: `${tool.title || tool.toolName} · ${tool.toolCode}`,
|
||||||
|
})),
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(
|
toast.error(
|
||||||
error instanceof Error ? error.message : "加载 Direct Tools 失败",
|
error instanceof Error ? error.message : "加载 Direct Tools 失败",
|
||||||
@@ -470,10 +494,7 @@ function EditDialogBody({
|
|||||||
const directToolsGrouped = useMemo(() => {
|
const directToolsGrouped = useMemo(() => {
|
||||||
const groups = new Map<string, DirectToolItem[]>();
|
const groups = new Map<string, DirectToolItem[]>();
|
||||||
for (const tool of directTools) {
|
for (const tool of directTools) {
|
||||||
const groupLabel =
|
const groupLabel = tool.serverCode || "未分组";
|
||||||
tool.serverCode === "builtin" || tool.toolCode.startsWith("builtin/")
|
|
||||||
? "内置工具"
|
|
||||||
: tool.serverCode || "未分组";
|
|
||||||
const current = groups.get(groupLabel) ?? [];
|
const current = groups.get(groupLabel) ?? [];
|
||||||
current.push(tool);
|
current.push(tool);
|
||||||
groups.set(groupLabel, current);
|
groups.set(groupLabel, current);
|
||||||
@@ -481,6 +502,14 @@ function EditDialogBody({
|
|||||||
return Array.from(groups.entries());
|
return Array.from(groups.entries());
|
||||||
}, [directTools]);
|
}, [directTools]);
|
||||||
|
|
||||||
|
const addableGraphToolOptions = useMemo(
|
||||||
|
() =>
|
||||||
|
graphToolOptions.filter(
|
||||||
|
(option) => !graphTools.includes(option.value),
|
||||||
|
),
|
||||||
|
[graphToolOptions, graphTools],
|
||||||
|
);
|
||||||
|
|
||||||
const addableTeamOptions = useMemo(
|
const addableTeamOptions = useMemo(
|
||||||
() =>
|
() =>
|
||||||
teamOptions.filter(
|
teamOptions.filter(
|
||||||
@@ -512,6 +541,7 @@ function EditDialogBody({
|
|||||||
selectedTeamIds,
|
selectedTeamIds,
|
||||||
selectedSkillIds,
|
selectedSkillIds,
|
||||||
directTools,
|
directTools,
|
||||||
|
graphTools,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -593,6 +623,18 @@ function EditDialogBody({
|
|||||||
setDirectTools((prev) => prev.filter((item) => item.toolCode !== value));
|
setDirectTools((prev) => prev.filter((item) => item.toolCode !== value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAddGraphTool(value: string) {
|
||||||
|
if (!value || graphTools.includes(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setGraphTools((prev) => [...prev, value]);
|
||||||
|
setGraphToolToAdd("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemoveGraphTool(value: string) {
|
||||||
|
setGraphTools((prev) => prev.filter((item) => item !== value));
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProjectDialog
|
<ProjectDialog
|
||||||
open={open}
|
open={open}
|
||||||
@@ -700,9 +742,9 @@ function EditDialogBody({
|
|||||||
|
|
||||||
<SectionCard
|
<SectionCard
|
||||||
title="能力配置"
|
title="能力配置"
|
||||||
description="知识库用于 RAG,Skills 用于业务流程,Direct Tools 用于低风险实时查询。"
|
description="知识库用于 RAG,Skills 用于业务流程,Direct Tools 用于外部 MCP 查询,Graph Tools 用于内置业务流程。"
|
||||||
>
|
>
|
||||||
<div className="grid gap-4 xl:grid-cols-3">
|
<div className="grid gap-4 xl:grid-cols-4">
|
||||||
<div className="rounded-xl border bg-muted/10 p-4">
|
<div className="rounded-xl border bg-muted/10 p-4">
|
||||||
<div className="mb-1 text-sm font-medium">知识库</div>
|
<div className="mb-1 text-sm font-medium">知识库</div>
|
||||||
<div className="mb-4 text-xs text-muted-foreground">
|
<div className="mb-4 text-xs text-muted-foreground">
|
||||||
@@ -854,8 +896,7 @@ function EditDialogBody({
|
|||||||
<div className="rounded-xl border bg-muted/10 p-4">
|
<div className="rounded-xl border bg-muted/10 p-4">
|
||||||
<div className="mb-1 text-sm font-medium">Direct Tools</div>
|
<div className="mb-1 text-sm font-medium">Direct Tools</div>
|
||||||
<div className="mb-4 text-xs text-muted-foreground">
|
<div className="mb-4 text-xs text-muted-foreground">
|
||||||
用于低风险、原子化的实时查询。可选择 MCP 工具,也可选择系统内置工具。
|
仅用于外部 MCP 工具的低风险、原子化查询。
|
||||||
`tool_search` 会由 Runtime 自动注入,这里不需要手动添加。
|
|
||||||
</div>
|
</div>
|
||||||
<Field>
|
<Field>
|
||||||
<FieldContent className="space-y-3">
|
<FieldContent className="space-y-3">
|
||||||
@@ -923,9 +964,7 @@ function EditDialogBody({
|
|||||||
>
|
>
|
||||||
{tool.title || catalogItem?.title || value}
|
{tool.title || catalogItem?.title || value}
|
||||||
<span className="text-[10px] text-muted-foreground/80">
|
<span className="text-[10px] text-muted-foreground/80">
|
||||||
{catalogItem?.sourceType === "builtin"
|
{tool.serverCode || "MCP"}
|
||||||
? "内置"
|
|
||||||
: tool.serverCode || "MCP"}
|
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -950,6 +989,73 @@ function EditDialogBody({
|
|||||||
</FieldContent>
|
</FieldContent>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="rounded-xl border bg-muted/10 p-4">
|
||||||
|
<div className="mb-1 text-sm font-medium">Graph Tools</div>
|
||||||
|
<div className="mb-4 text-xs text-muted-foreground">
|
||||||
|
用于建单、转人工等系统内置流程,不再混放到 Direct Tools 中。
|
||||||
|
</div>
|
||||||
|
<Field>
|
||||||
|
<FieldContent className="space-y-3">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="flex-1">
|
||||||
|
<OptionCombobox
|
||||||
|
value={graphToolToAdd}
|
||||||
|
options={addableGraphToolOptions}
|
||||||
|
placeholder="选择 Graph Tool"
|
||||||
|
searchPlaceholder="搜索 Graph Tool"
|
||||||
|
emptyText="没有可添加的 Graph Tool"
|
||||||
|
onChange={handleAddGraphTool}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
disabled={!graphToolToAdd}
|
||||||
|
onClick={() => handleAddGraphTool(graphToolToAdd)}
|
||||||
|
>
|
||||||
|
<PlusIcon />
|
||||||
|
添加
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{graphTools.length === 0 ? (
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
不配置 Graph Tool 时,Agent 不会暴露建单/转人工等内置流程工具。
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
graphTools.map((toolCode) => {
|
||||||
|
const catalogItem = toolCatalog.find(
|
||||||
|
(item) => item.toolCode === toolCode,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
key={toolCode}
|
||||||
|
variant="secondary"
|
||||||
|
className="gap-1 pr-1"
|
||||||
|
>
|
||||||
|
{catalogItem?.title || toolCode}
|
||||||
|
<span className="text-[10px] text-muted-foreground/80">
|
||||||
|
graph
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="size-5"
|
||||||
|
onClick={() => handleRemoveGraphTool(toolCode)}
|
||||||
|
aria-label={`移除 Graph Tool ${toolCode}`}
|
||||||
|
>
|
||||||
|
<Trash2Icon className="size-3" />
|
||||||
|
</Button>
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</FieldContent>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SectionCard>
|
</SectionCard>
|
||||||
|
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ export type AIAgent = {
|
|||||||
description: string
|
description: string
|
||||||
arguments?: Record<string, string>
|
arguments?: Record<string, string>
|
||||||
}[]
|
}[]
|
||||||
|
graphTools: string[]
|
||||||
sortNo: number
|
sortNo: number
|
||||||
remark: string
|
remark: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
@@ -249,6 +250,7 @@ export type CreateAIAgentPayload = {
|
|||||||
description: string
|
description: string
|
||||||
arguments?: Record<string, string>
|
arguments?: Record<string, string>
|
||||||
}[]
|
}[]
|
||||||
|
graphTools: string[]
|
||||||
remark: string
|
remark: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user