Files
ai-agent/workflow/service/node/node_library_service.go
T
19904408334 cef837a35c feat: 支持工作流断点续跑并拆分错误信息存储
- 新增同会话+同工作流最近执行失败且参数一致时断点续跑逻辑
- exec_workflow/exec_chat 新增 error 字段存储原始错误,error_message 仅存友好提示
- 新增 UpdateExecChatReq 与 exec_chat_dao Update 方法
- 新增 GetLatestBySessionAndFlow 查询最近执行记录
- 修正 ListDates 分组与排序 SQL 表达式
- 新增 pipeline 配置结构,删除旧设计文档
2026-08-21 09:54:06 +08:00

128 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package node
import (
"context"
"strconv"
"ai-agent/gateway"
"ai-agent/workflow/consts/model"
"ai-agent/workflow/consts/node"
nodeDto "ai-agent/workflow/model/dto/node"
"ai-agent/workflow/service/flow/processor"
"github.com/gogf/gf/v2/frame/g"
)
var NodeLibraryService = &nodeLibraryService{}
type nodeLibraryService struct{}
func (s *nodeLibraryService) GetNodeLibrary(ctx context.Context, req *nodeDto.WorkflowNodeTreeReq) (*nodeDto.WorkflowNodeTreeRes, error) {
tree := node.GetFilterNodeTree([]node.NodeGroup{node.NodeGroupBase})
if opts, err := videoModelOptions(ctx); err != nil {
g.Log().Warningf(ctx, "加载视频模型选项失败,节点库降级返回: %v", err)
} else {
applyVideoModelOptions(tree, opts)
}
// 前置/后置方法下拉填充处理器注册表数据
if opts, err := processorOptions(ctx); err != nil {
g.Log().Warningf(ctx, "加载工作流前后置处理器选项失败,节点库降级返回: %v", err)
} else {
applyProcessorOptions(tree, opts)
}
return &nodeDto.WorkflowNodeTreeRes{
Groups: tree,
}, nil
}
// processorOptions 从处理器注册表构建前置/后置方法下拉选项:key=处理器名,value=描述(无描述回落名称)。
func processorOptions(ctx context.Context) ([]node.SelectOption, error) {
list, err := processor.List(ctx)
if err != nil {
return nil, err
}
opts := make([]node.SelectOption, 0, len(list))
for _, p := range list {
if p == nil || p.Name == "" || !p.IsShow {
continue
}
value := p.Description
if value == "" {
value = p.Name
}
opts = append(opts, node.SelectOption{
Key: p.Name,
Value: value,
})
}
return opts, nil
}
// applyProcessorOptions 把处理器选项填充进模型节点的 preTool/postTool 下拉。
// 深拷贝 PreToolOption/PostToolOption 后再改,避免改写全局 NodeTypeMetaList。
func applyProcessorOptions(tree []node.NodeGroupTree, opts []node.SelectOption) {
for gi := range tree {
for ni := range tree[gi].Nodes {
n := &tree[gi].Nodes[ni]
if n.Key != node.NodeTypeModel {
continue
}
n.PreToolOption = withProcessorOptions(n.PreToolOption, opts)
n.PostToolOption = withProcessorOptions(n.PostToolOption, opts)
return
}
}
}
// withProcessorOptions 返回 preTool/postTool 字段列表的深拷贝,并把 select 类型字段的 Options 替换为处理器选项。
func withProcessorOptions(fields []node.NodePresetField, opts []node.SelectOption) []node.NodePresetField {
out := append([]node.NodePresetField(nil), fields...)
for i := range out {
if out[i].Type == "select" {
out[i].Options = opts
}
}
return out
}
// videoModelOptions 按视频模型类型(600)查模型网关,转成 modelId 下拉选项:key=模型IDvalue=模型名称。
func videoModelOptions(ctx context.Context) ([]node.SelectOption, error) {
res, err := gateway.ListModelManage(ctx, &gateway.ListModelManageReq{ModelType: model.TypeVideo})
if err != nil {
return nil, err
}
opts := make([]node.SelectOption, 0, len(res.List))
for _, item := range res.List {
if item == nil || item.Id <= 0 || item.ModelName == "" {
continue
}
opts = append(opts, node.SelectOption{
Key: strconv.FormatInt(item.Id, 10),
Value: item.ModelName,
})
}
return opts, nil
}
// applyVideoModelOptions 把 script_transcribe 节点的 modelId 预设下拉替换为视频模型选项。
// 深拷贝 PresetOption 后再改,避免改写全局 NodeTypeMetaList。
func applyVideoModelOptions(tree []node.NodeGroupTree, opts []node.SelectOption) {
for gi := range tree {
for ni := range tree[gi].Nodes {
n := &tree[gi].Nodes[ni]
if n.Key != node.NodeTypeScriptTranscribe {
continue
}
presets := append([]node.NodePresetField(nil), n.PresetOption...)
for pi := range presets {
if presets[pi].Field == "modelId" {
presets[pi].Options = opts
break
}
}
n.PresetOption = presets
return
}
}
}