diff --git a/internal/ai/runtime/executor/tooling.go b/internal/ai/runtime/executor/tooling.go index 2766e9e..e3b1d14 100644 --- a/internal/ai/runtime/executor/tooling.go +++ b/internal/ai/runtime/executor/tooling.go @@ -4,8 +4,8 @@ import ( "encoding/json" "strings" - "cs-agent/internal/ai/runtime/internal/impl/adapter" "cs-agent/internal/ai/runtime/registry" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" @@ -13,7 +13,7 @@ import ( ) type preparedTooling struct { - definitions []adapter.MCPToolDefinition + definitions []runtimetooling.MCPToolDefinition toolCodes []string toolDefsByModelName map[string]string staticToolCodes []string @@ -22,7 +22,7 @@ type preparedTooling struct { staticToolMetadata map[string]registry.ToolMetadata } -func prepareTooling(defs []adapter.MCPToolDefinition, selectedSkill *models.SkillDefinition, toolSet *registry.ToolSet, includeSkillTool bool) preparedTooling { +func prepareTooling(defs []runtimetooling.MCPToolDefinition, selectedSkill *models.SkillDefinition, toolSet *registry.ToolSet, includeSkillTool bool) preparedTooling { filteredDefs := filterToolDefinitionsBySkill(defs, selectedSkill) ret := preparedTooling{ definitions: filteredDefs, @@ -125,7 +125,7 @@ func staticToolCodeList(toolSet *registry.ToolSet) []string { return ret } -func definitionToolCodes(defs []adapter.MCPToolDefinition) []string { +func definitionToolCodes(defs []runtimetooling.MCPToolDefinition) []string { ret := make([]string, 0, len(defs)) for _, item := range defs { code := strings.TrimSpace(item.ToolCode) @@ -137,7 +137,7 @@ func definitionToolCodes(defs []adapter.MCPToolDefinition) []string { return ret } -func filterToolDefinitionsBySkill(defs []adapter.MCPToolDefinition, skill *models.SkillDefinition) []adapter.MCPToolDefinition { +func filterToolDefinitionsBySkill(defs []runtimetooling.MCPToolDefinition, skill *models.SkillDefinition) []runtimetooling.MCPToolDefinition { if skill == nil || strings.TrimSpace(skill.ToolWhitelist) == "" { return defs } @@ -156,7 +156,7 @@ func filterToolDefinitionsBySkill(defs []adapter.MCPToolDefinition, skill *model if len(allowedSet) == 0 { return defs } - ret := make([]adapter.MCPToolDefinition, 0, len(defs)) + ret := make([]runtimetooling.MCPToolDefinition, 0, len(defs)) for _, item := range defs { if _, ok := allowedSet[strings.TrimSpace(item.ToolCode)]; ok { ret = append(ret, item) diff --git a/internal/ai/runtime/internal/impl/adapter/mcp_tool_adapter.go b/internal/ai/runtime/internal/impl/adapter/mcp_tool_adapter.go index eddc817..db0f81c 100644 --- a/internal/ai/runtime/internal/impl/adapter/mcp_tool_adapter.go +++ b/internal/ai/runtime/internal/impl/adapter/mcp_tool_adapter.go @@ -4,11 +4,10 @@ import ( "context" "encoding/json" "fmt" - "hash/crc32" - "regexp" "strings" "cs-agent/internal/ai/mcps" + runtimetooling "cs-agent/internal/ai/runtime/tooling" einojsonschema "github.com/eino-contrib/jsonschema" @@ -16,17 +15,7 @@ import ( "github.com/cloudwego/eino/schema" ) -var toolNameSanitizer = regexp.MustCompile(`[^a-zA-Z0-9_]`) - -type MCPToolDefinition struct { - ToolCode string - ServerCode string - ToolName string - ModelName string - Title string - Description string - FixedArgs map[string]string -} +type MCPToolDefinition = runtimetooling.MCPToolDefinition type MCPTool struct { definition MCPToolDefinition @@ -83,7 +72,7 @@ func buildToolInfo(definition MCPToolDefinition, metadata *mcps.ToolInfo) *schem desc = "Call MCP tool " + strings.TrimSpace(definition.ToolCode) } info := &schema.ToolInfo{ - Name: BuildModelToolName(definition), + Name: runtimetooling.BuildModelToolName(definition), Desc: desc, Extra: map[string]any{ "toolCode": definition.ToolCode, @@ -145,17 +134,3 @@ func mergeFixedArguments(arguments map[string]any, fixedArgs map[string]string) } return ret } - -func BuildModelToolName(definition MCPToolDefinition) string { - if strings.TrimSpace(definition.ModelName) != "" { - return strings.TrimSpace(definition.ModelName) - } - base := "mcp_" + strings.TrimSpace(definition.ServerCode) + "_" + strings.TrimSpace(definition.ToolName) - base = toolNameSanitizer.ReplaceAllString(base, "_") - base = strings.Trim(base, "_") - if base == "" { - base = "mcp_tool" - } - checksum := crc32.ChecksumIEEE([]byte(definition.ToolCode)) - return fmt.Sprintf("%s_%08x", base, checksum) -} diff --git a/internal/ai/runtime/internal/impl/factory/agent_factory.go b/internal/ai/runtime/internal/impl/factory/agent_factory.go index fd93b14..4d79600 100644 --- a/internal/ai/runtime/internal/impl/factory/agent_factory.go +++ b/internal/ai/runtime/internal/impl/factory/agent_factory.go @@ -4,10 +4,10 @@ import ( "context" "strings" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" einoagents "cs-agent/internal/ai/runtime/internal/impl/agents" einocallbacks "cs-agent/internal/ai/runtime/internal/impl/callbacks" "cs-agent/internal/ai/runtime/registry" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "github.com/cloudwego/eino/adk" @@ -37,10 +37,10 @@ type BuildCustomerServiceAgentInput struct { SelectedSkill *models.SkillDefinition // InstructionToolDefinitions 用于生成 instruction 中的工具说明。 // 它描述“当前允许模型理解和使用的 MCP 工具范围”。 - InstructionToolDefinitions []einoadapter.MCPToolDefinition + InstructionToolDefinitions []runtimetooling.MCPToolDefinition // DynamicMCPToolDefinitions 用于接入 Eino tool_search middleware 的动态工具集合。 // 这些工具默认不直接挂在 ToolsNode 上,而是经 tool_search 选择后再暴露给模型。 - DynamicMCPToolDefinitions []einoadapter.MCPToolDefinition + DynamicMCPToolDefinitions []runtimetooling.MCPToolDefinition // StaticTools 为当前运行时直接挂载到 ToolsNode 的固定工具,例如 Graph Tool。 StaticTools []einobasetool.BaseTool // StaticToolCodes 为固定工具的 modelName -> toolCode 映射,用于 trace 和运行日志归因。 diff --git a/internal/ai/runtime/internal/impl/factory/agent_handler_service.go b/internal/ai/runtime/internal/impl/factory/agent_handler_service.go index fcdfae5..285cc34 100644 --- a/internal/ai/runtime/internal/impl/factory/agent_handler_service.go +++ b/internal/ai/runtime/internal/impl/factory/agent_handler_service.go @@ -3,9 +3,9 @@ package factory import ( "context" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" einocallbacks "cs-agent/internal/ai/runtime/internal/impl/callbacks" "cs-agent/internal/ai/runtime/registry" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" @@ -20,8 +20,8 @@ type AgentHandlerService struct { type BuildAgentHandlersInput struct { SelectedSkill *models.SkillDefinition - InstructionToolDefinitions []einoadapter.MCPToolDefinition - DynamicToolDefinitions []einoadapter.MCPToolDefinition + InstructionToolDefinitions []runtimetooling.MCPToolDefinition + DynamicToolDefinitions []runtimetooling.MCPToolDefinition DynamicTools []einobasetool.BaseTool StaticToolMetadata map[string]registry.ToolMetadata Collector *einocallbacks.RuntimeTraceCollector diff --git a/internal/ai/runtime/internal/impl/factory/instruction_providers.go b/internal/ai/runtime/internal/impl/factory/instruction_providers.go index a1f6874..77759c5 100644 --- a/internal/ai/runtime/internal/impl/factory/instruction_providers.go +++ b/internal/ai/runtime/internal/impl/factory/instruction_providers.go @@ -5,7 +5,7 @@ import ( "path/filepath" "strings" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" ) @@ -87,7 +87,7 @@ func (p *SkillInstructionProvider) Resolve(selectedSkill *models.SkillDefinition return buildSelectedSkillActivationInstruction(selectedSkill) } -func (p *ToolAppendixProvider) Build(toolDefinitions []einoadapter.MCPToolDefinition, extraToolCodes map[string]string) []string { +func (p *ToolAppendixProvider) Build(toolDefinitions []runtimetooling.MCPToolDefinition, extraToolCodes map[string]string) []string { appendixParts := make([]string, 0, 1) toolCodes := make([]string, 0, len(toolDefinitions)+len(extraToolCodes)) for _, item := range toolDefinitions { diff --git a/internal/ai/runtime/internal/impl/factory/instruction_service.go b/internal/ai/runtime/internal/impl/factory/instruction_service.go index 5210789..ec24580 100644 --- a/internal/ai/runtime/internal/impl/factory/instruction_service.go +++ b/internal/ai/runtime/internal/impl/factory/instruction_service.go @@ -3,7 +3,7 @@ package factory import ( "strings" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" ) @@ -49,7 +49,7 @@ func NewInstructionService( func (s *InstructionService) Build( aiAgent *models.AIAgent, selectedSkill *models.SkillDefinition, - toolDefinitions []einoadapter.MCPToolDefinition, + toolDefinitions []runtimetooling.MCPToolDefinition, extraToolCodes map[string]string, ) InstructionAssemblyResult { baseInstruction := "" diff --git a/internal/ai/runtime/internal/impl/factory/skill_instruction_helpers.go b/internal/ai/runtime/internal/impl/factory/skill_instruction_helpers.go index a34ceff..8f10251 100644 --- a/internal/ai/runtime/internal/impl/factory/skill_instruction_helpers.go +++ b/internal/ai/runtime/internal/impl/factory/skill_instruction_helpers.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" ) @@ -26,7 +26,7 @@ func buildSelectedSkillActivationInstruction(skill *models.SkillDefinition) stri return strings.TrimSpace(strings.Join(lines, "\n")) } -func buildSelectedSkillDocument(skill *models.SkillDefinition, toolDefinitions []einoadapter.MCPToolDefinition) string { +func buildSelectedSkillDocument(skill *models.SkillDefinition, toolDefinitions []runtimetooling.MCPToolDefinition) string { if skill == nil { return "" } diff --git a/internal/ai/runtime/internal/impl/factory/skill_middleware_backend.go b/internal/ai/runtime/internal/impl/factory/skill_middleware_backend.go index 31b96fc..316a3ef 100644 --- a/internal/ai/runtime/internal/impl/factory/skill_middleware_backend.go +++ b/internal/ai/runtime/internal/impl/factory/skill_middleware_backend.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" einoskill "github.com/cloudwego/eino/adk/middlewares/skill" @@ -16,7 +16,7 @@ type selectedSkillBackend struct { skill einoskill.Skill } -func newSelectedSkillBackend(selectedSkill *models.SkillDefinition, toolDefinitions []einoadapter.MCPToolDefinition) (*selectedSkillBackend, error) { +func newSelectedSkillBackend(selectedSkill *models.SkillDefinition, toolDefinitions []runtimetooling.MCPToolDefinition) (*selectedSkillBackend, error) { if selectedSkill == nil { return nil, fmt.Errorf("selected skill is nil") } diff --git a/internal/ai/runtime/internal/impl/factory/skill_middleware_service.go b/internal/ai/runtime/internal/impl/factory/skill_middleware_service.go index 3ce5b66..b7c8255 100644 --- a/internal/ai/runtime/internal/impl/factory/skill_middleware_service.go +++ b/internal/ai/runtime/internal/impl/factory/skill_middleware_service.go @@ -3,7 +3,7 @@ package factory import ( "context" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" @@ -20,7 +20,7 @@ func NewSkillMiddlewareService() *SkillMiddlewareService { func (s *SkillMiddlewareService) Build( ctx context.Context, selectedSkill *models.SkillDefinition, - toolDefinitions []einoadapter.MCPToolDefinition, + toolDefinitions []runtimetooling.MCPToolDefinition, ) (adk.ChatModelAgentMiddleware, error) { backend, err := newSelectedSkillBackend(selectedSkill, toolDefinitions) if err != nil { diff --git a/internal/ai/runtime/internal/impl/factory/tool_factory.go b/internal/ai/runtime/internal/impl/factory/tool_factory.go index 0e18da1..dc54d18 100644 --- a/internal/ai/runtime/internal/impl/factory/tool_factory.go +++ b/internal/ai/runtime/internal/impl/factory/tool_factory.go @@ -6,6 +6,7 @@ import ( "cs-agent/internal/ai/mcps" impladapter "cs-agent/internal/ai/runtime/internal/impl/adapter" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" @@ -18,7 +19,7 @@ func NewToolFactory() *ToolFactory { return &ToolFactory{} } -func (f *ToolFactory) BuildMCPTools(aiAgent *models.AIAgent) ([]impladapter.MCPToolDefinition, error) { +func (f *ToolFactory) BuildMCPTools(aiAgent *models.AIAgent) ([]runtimetooling.MCPToolDefinition, error) { if aiAgent == nil || strings.TrimSpace(aiAgent.AllowedMCPTools) == "" { return nil, nil } @@ -26,7 +27,7 @@ func (f *ToolFactory) BuildMCPTools(aiAgent *models.AIAgent) ([]impladapter.MCPT if err != nil { return nil, err } - ret := make([]impladapter.MCPToolDefinition, 0, len(raw)) + ret := make([]runtimetooling.MCPToolDefinition, 0, len(raw)) for _, item := range raw { toolCode := strings.TrimSpace(item.ToolCode) toolCode = toolx.NormalizeToolCodeAlias(toolCode) @@ -37,7 +38,7 @@ func (f *ToolFactory) BuildMCPTools(aiAgent *models.AIAgent) ([]impladapter.MCPT if serverCode == "" || toolName == "" { continue } - definition := impladapter.MCPToolDefinition{ + definition := runtimetooling.MCPToolDefinition{ ToolCode: toolCode, ServerCode: serverCode, ToolName: toolName, @@ -45,7 +46,7 @@ func (f *ToolFactory) BuildMCPTools(aiAgent *models.AIAgent) ([]impladapter.MCPT Description: strings.TrimSpace(item.Description), FixedArgs: cloneStringMap(item.Arguments), } - definition.ModelName = impladapter.BuildModelToolName(definition) + definition.ModelName = runtimetooling.BuildModelToolName(definition) ret = append(ret, definition) } return ret, nil @@ -59,7 +60,7 @@ func (f *ToolFactory) BuildBaseTools(ctx context.Context, aiAgent *models.AIAgen return f.BuildBaseToolsByDefinitions(ctx, definitions) } -func (f *ToolFactory) BuildBaseToolsByDefinitions(ctx context.Context, definitions []impladapter.MCPToolDefinition) ([]einotool.BaseTool, error) { +func (f *ToolFactory) BuildBaseToolsByDefinitions(ctx context.Context, definitions []runtimetooling.MCPToolDefinition) ([]einotool.BaseTool, error) { if len(definitions) == 0 { return nil, nil } @@ -74,7 +75,7 @@ func (f *ToolFactory) BuildBaseToolsByDefinitions(ctx context.Context, definitio return ret, nil } -func (f *ToolFactory) loadToolMetadata(ctx context.Context, definitions []impladapter.MCPToolDefinition) (map[string]*mcps.ToolInfo, error) { +func (f *ToolFactory) loadToolMetadata(ctx context.Context, definitions []runtimetooling.MCPToolDefinition) (map[string]*mcps.ToolInfo, error) { toolsByCode := make(map[string]*mcps.ToolInfo, len(definitions)) serverCodes := make(map[string]struct{}) for _, item := range definitions { diff --git a/internal/ai/runtime/internal/impl/factory/tool_helpers.go b/internal/ai/runtime/internal/impl/factory/tool_helpers.go index 7aaaf50..57f63e4 100644 --- a/internal/ai/runtime/internal/impl/factory/tool_helpers.go +++ b/internal/ai/runtime/internal/impl/factory/tool_helpers.go @@ -3,9 +3,9 @@ package factory import ( "strings" - einoadapter "cs-agent/internal/ai/runtime/internal/impl/adapter" einocallbacks "cs-agent/internal/ai/runtime/internal/impl/callbacks" "cs-agent/internal/ai/runtime/registry" + runtimetooling "cs-agent/internal/ai/runtime/tooling" "cs-agent/internal/models" "cs-agent/internal/pkg/toolx" ) @@ -22,7 +22,7 @@ func buildInstructionTraceSummary(summary InstructionAssemblySummary) einocallba } func buildRuntimeTraceToolMetadata( - dynamicToolDefinitions []einoadapter.MCPToolDefinition, + dynamicToolDefinitions []runtimetooling.MCPToolDefinition, staticToolMetadata map[string]registry.ToolMetadata, selectedSkill *models.SkillDefinition, ) map[string]einocallbacks.ToolMetadata { diff --git a/internal/ai/runtime/tooling/mcp_tool_definition.go b/internal/ai/runtime/tooling/mcp_tool_definition.go new file mode 100644 index 0000000..bae02b8 --- /dev/null +++ b/internal/ai/runtime/tooling/mcp_tool_definition.go @@ -0,0 +1,34 @@ +package tooling + +import ( + "fmt" + "hash/crc32" + "regexp" + "strings" +) + +var toolNameSanitizer = regexp.MustCompile(`[^a-zA-Z0-9_]`) + +type MCPToolDefinition struct { + ToolCode string + ServerCode string + ToolName string + ModelName string + Title string + Description string + FixedArgs map[string]string +} + +func BuildModelToolName(definition MCPToolDefinition) string { + if strings.TrimSpace(definition.ModelName) != "" { + return strings.TrimSpace(definition.ModelName) + } + base := "mcp_" + strings.TrimSpace(definition.ServerCode) + "_" + strings.TrimSpace(definition.ToolName) + base = toolNameSanitizer.ReplaceAllString(base, "_") + base = strings.Trim(base, "_") + if base == "" { + base = "mcp_tool" + } + checksum := crc32.ChecksumIEEE([]byte(definition.ToolCode)) + return fmt.Sprintf("%s_%08x", base, checksum) +}