diff --git a/internal/ai/runtime/internal/impl/factory/agent_factory.go b/internal/ai/runtime/internal/impl/factory/agent_factory.go index 4c41394..d4bf1e1 100644 --- a/internal/ai/runtime/internal/impl/factory/agent_factory.go +++ b/internal/ai/runtime/internal/impl/factory/agent_factory.go @@ -96,38 +96,8 @@ func (f *AgentFactory) BuildCustomerServiceAgent(ctx context.Context, input Buil handlers = append(handlers, skillHandler) } if input.Collector != nil { - toolMetadataBy := make(map[string]einocallbacks.ToolMetadata, len(input.DynamicMCPToolDefinitions)+len(input.StaticToolMetadata)) - for _, item := range input.DynamicMCPToolDefinitions { - toolMetadataBy[item.ModelName] = einocallbacks.ToolMetadata{ - ToolCode: item.ToolCode, - ServerCode: item.ServerCode, - ToolName: item.ToolName, - SourceType: "mcp", - } - } - for modelName, metadata := range input.StaticToolMetadata { - modelName = strings.TrimSpace(modelName) - metadata.ToolCode = strings.TrimSpace(metadata.ToolCode) - metadata.ServerCode = strings.TrimSpace(metadata.ServerCode) - metadata.ToolName = strings.TrimSpace(metadata.ToolName) - metadata.SourceType = strings.TrimSpace(metadata.SourceType) - if modelName == "" || metadata.ToolCode == "" { - continue - } - toolMetadataBy[modelName] = einocallbacks.ToolMetadata{ - ToolCode: metadata.ToolCode, - ServerCode: metadata.ServerCode, - ToolName: metadata.ToolName, - SourceType: metadata.SourceType, - } - } + toolMetadataBy := buildRuntimeTraceToolMetadata(input.DynamicMCPToolDefinitions, input.StaticToolMetadata, input.SelectedSkill) if input.SelectedSkill != nil { - toolMetadataBy[toolx.BuiltinSkill.Name] = einocallbacks.ToolMetadata{ - ToolCode: toolx.BuiltinSkill.Code, - ServerCode: toolx.BuiltinSkill.ServerCode, - ToolName: toolx.BuiltinSkill.Name, - SourceType: toolx.BuiltinSkill.SourceType, - } input.Collector.SetSkillMiddleware(true, toolx.BuiltinSkill.Name) } handlers = append(handlers, einocallbacks.NewRuntimeTraceHandler(input.Collector, toolMetadataBy)) @@ -179,11 +149,7 @@ func assembleAgentInstruction(aiAgent *models.AIAgent, selectedSkill *models.Ski if aiAgent != nil { baseInstruction = strings.TrimSpace(aiAgent.SystemPrompt) } - appendixParts := make([]string, 0, 2) - if skillInstruction := buildSelectedSkillActivationInstruction(selectedSkill); skillInstruction != "" { - appendixParts = append(appendixParts, skillInstruction) - } - appendixParts = append(appendixParts, toolx.BuildToolAppendices(len(toolDefinitions) > 0, extraToolCodes)...) + appendixParts := buildInstructionAppendices(selectedSkill, toolDefinitions, extraToolCodes) return NewInstructionAssembler().Assemble(InstructionAssemblerInput{ AgentInstruction: baseInstruction, SkillInstruction: firstAppendixPart(appendixParts), diff --git a/internal/ai/runtime/internal/impl/factory/tool_helpers.go b/internal/ai/runtime/internal/impl/factory/tool_helpers.go new file mode 100644 index 0000000..24b3f2e --- /dev/null +++ b/internal/ai/runtime/internal/impl/factory/tool_helpers.go @@ -0,0 +1,72 @@ +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" + "cs-agent/internal/models" + "cs-agent/internal/pkg/toolx" +) + +func buildRuntimeTraceToolMetadata( + dynamicToolDefinitions []einoadapter.MCPToolDefinition, + staticToolMetadata map[string]registry.ToolMetadata, + selectedSkill *models.SkillDefinition, +) map[string]einocallbacks.ToolMetadata { + ret := make(map[string]einocallbacks.ToolMetadata, len(dynamicToolDefinitions)+len(staticToolMetadata)+1) + for _, item := range dynamicToolDefinitions { + modelName := strings.TrimSpace(item.ModelName) + if modelName == "" { + continue + } + ret[modelName] = einocallbacks.ToolMetadata{ + ToolCode: strings.TrimSpace(item.ToolCode), + ServerCode: strings.TrimSpace(item.ServerCode), + ToolName: strings.TrimSpace(item.ToolName), + SourceType: "mcp", + } + } + for modelName, metadata := range staticToolMetadata { + modelName = strings.TrimSpace(modelName) + metadata.ToolCode = strings.TrimSpace(metadata.ToolCode) + metadata.ServerCode = strings.TrimSpace(metadata.ServerCode) + metadata.ToolName = strings.TrimSpace(metadata.ToolName) + metadata.SourceType = strings.TrimSpace(metadata.SourceType) + if modelName == "" || metadata.ToolCode == "" { + continue + } + ret[modelName] = einocallbacks.ToolMetadata{ + ToolCode: metadata.ToolCode, + ServerCode: metadata.ServerCode, + ToolName: metadata.ToolName, + SourceType: metadata.SourceType, + } + } + if selectedSkill != nil { + ret[toolx.BuiltinSkill.Name] = einocallbacks.ToolMetadata{ + ToolCode: toolx.BuiltinSkill.Code, + ServerCode: toolx.BuiltinSkill.ServerCode, + ToolName: toolx.BuiltinSkill.Name, + SourceType: toolx.BuiltinSkill.SourceType, + } + } + return ret +} + +func buildInstructionAppendices(selectedSkill *models.SkillDefinition, toolDefinitions []einoadapter.MCPToolDefinition, extraToolCodes map[string]string) []string { + appendixParts := make([]string, 0, 2) + if skillInstruction := buildSelectedSkillActivationInstruction(selectedSkill); skillInstruction != "" { + appendixParts = append(appendixParts, skillInstruction) + } + toolCodes := make([]string, 0, len(toolDefinitions)+len(extraToolCodes)) + for _, item := range toolDefinitions { + toolCodes = append(toolCodes, item.ToolCode) + } + for _, item := range extraToolCodes { + toolCodes = append(toolCodes, item) + } + appendixParts = append(appendixParts, toolx.BuildToolAppendicesForCodes(len(toolDefinitions) > 0, toolCodes)...) + return appendixParts +} diff --git a/internal/pkg/toolx/builtin_tools.go b/internal/pkg/toolx/builtin_tools.go index 45e51d3..e5d4067 100644 --- a/internal/pkg/toolx/builtin_tools.go +++ b/internal/pkg/toolx/builtin_tools.go @@ -279,7 +279,12 @@ func NormalizeToolCodeAlias(toolCode string) string { } func BuildToolAppendices(hasDynamicMCPTools bool, toolCodes map[string]string) []string { + return BuildToolAppendicesForCodes(hasDynamicMCPTools, toolCodesFromMap(toolCodes)) +} + +func BuildToolAppendicesForCodes(hasDynamicMCPTools bool, toolCodes []string) []string { ret := make([]string, 0, len(toolCodes)+1) + normalizedToolCodes := NormalizeToolCodes(toolCodes) if hasDynamicMCPTools && strings.TrimSpace(BuiltinToolSearch.Appendix) != "" { ret = append(ret, BuiltinToolSearch.Appendix) } @@ -290,7 +295,7 @@ func BuildToolAppendices(hasDynamicMCPTools bool, toolCodes map[string]string) [ if spec.Code == BuiltinToolSearch.Code { continue } - if hasToolCode(toolCodes, spec.Code) { + if containsNormalizedToolCode(normalizedToolCodes, spec.Code) { ret = append(ret, spec.Appendix) } } @@ -330,18 +335,33 @@ func IsImpliedAllowedToolCode(toolCode string, allowedToolCodes map[string]struc } func hasToolCode(toolCodes map[string]string, target string) bool { + return containsNormalizedToolCode(toolCodesFromMap(toolCodes), target) +} + +func containsNormalizedToolCode(toolCodes []string, target string) bool { target = strings.TrimSpace(target) if target == "" || len(toolCodes) == 0 { return false } - for _, item := range toolCodes { - if NormalizeToolCodeAlias(strings.TrimSpace(item)) == target { + for _, item := range NormalizeToolCodes(toolCodes) { + if item == target { return true } } return false } +func toolCodesFromMap(toolCodes map[string]string) []string { + if len(toolCodes) == 0 { + return nil + } + ret := make([]string, 0, len(toolCodes)) + for _, item := range toolCodes { + ret = append(ret, item) + } + return ret +} + func NormalizeToolCodes(items []string) []string { if len(items) == 0 { return nil