Files
ttstd-infinite-canvas/backend/internal/tools/tool_mention.go
ddCat 9148ceab66 feat(canvas): 画布工作区 - 整合侧栏与风格预设并修复提示词回填
选择性整合 #547,保留主分支节点与工具条设计。新增默认折叠的节点、资产、任务和历史面板,风格与预设保留在节点内,移除重复入口。

补齐工具权限、提示词解析、资源引用保护及数据库迁移,修复提示词清空和连续编辑后的生成配置同步。

验证:前端全量 1925 项测试、构建、类型检查及 lint 通过;后端 go test ./... 通过。真实模型、PostgreSQL 实库与登录态页面验收仍待进行。

Refs #547

Co-authored-by: bensharp <bensharp@qq.com>
2026-09-20 16:40:08 +08:00

52 lines
1.8 KiB
Go

package tools
import (
"regexp"
"strconv"
"strings"
"infinite-canvas/backend/internal/kernel"
)
var toolMentionPattern = regexp.MustCompile(`@\[tool:(style|motion|nine_grid|effect):(\d+):[^:\]]+:[^\]]+\]`)
// ResolveToolMentionTokens validates every tool before expanding it. Labels and
// icons are presentation only; neither grants access to a private tool.
func (s *Service) ResolveToolMentionTokens(userID, mode, prompt string) (string, error) {
if !strings.Contains(prompt, "@[tool:") {
return prompt, nil
}
if strings.TrimSpace(userID) == "" {
return "", kernel.Unauthorized("请先登录")
}
if strings.Contains(toolMentionPattern.ReplaceAllString(prompt, ""), "@[tool:") {
return "", kernel.BadAuthRequest("工具标签无效,请重新选择工具")
}
prompts := make(map[string]string)
for _, match := range toolMentionPattern.FindAllStringSubmatch(prompt, -1) {
if _, ok := prompts[match[0]]; ok {
continue
}
id, err := strconv.ParseInt(match[2], 10, 64)
if err != nil || id <= 0 {
return "", kernel.BadAuthRequest("工具 ID 无效")
}
tool, err := s.repo.ToolForUser(userID, id)
if err != nil {
return "", err
}
if !tool.Enabled || tool.Type != match[1] {
return "", kernel.BadAuthRequest("工具已停用或类型不匹配")
}
imageTool := tool.Type == ToolTypeStyle || tool.Type == ToolTypeNineGrid
if (imageTool && mode != "image") || (!imageTool && mode != "video") {
return "", kernel.BadAuthRequest("工具不适用于当前生成类型")
}
if strings.TrimSpace(tool.Prompt) == "" || strings.Contains(tool.Prompt, "@[tool:") {
return "", kernel.BadAuthRequest("工具提示词为空或包含嵌套工具标签")
}
prompts[match[0]] = tool.Prompt
}
return toolMentionPattern.ReplaceAllStringFunc(prompt, func(token string) string { return prompts[token] }), nil
}