- Updated the BuildContent method to utilize content parsing with improved error handling and context injection, enhancing the processing of user input. - Refactored the loadMap function to support multiple search configuration types, improving flexibility in handling search settings. - Enhanced the shouldAutoSearch method to include a check for search disabling via context metadata, allowing for more granular control over search behavior. - Updated the getMergedSearchUses method to prioritize options.Uses, ensuring that search configurations can be dynamically adjusted based on provided options. - Removed deprecated audio and excel handling code, streamlining the content processing package and improving maintainability.
125 lines
3.5 KiB
Go
125 lines
3.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
jsoniter "github.com/json-iterator/go"
|
|
"github.com/yaoapp/gou/mcp"
|
|
"github.com/yaoapp/kun/log"
|
|
"github.com/yaoapp/yao/agent/caller"
|
|
agentContext "github.com/yaoapp/yao/agent/context"
|
|
)
|
|
|
|
// CallAgent calls an agent to process content (vision, audio, etc.)
|
|
func CallAgent(ctx *agentContext.Context, agentID string, message agentContext.Message) (string, error) {
|
|
if caller.AgentGetterFunc == nil {
|
|
return "", fmt.Errorf("AgentGetterFunc not initialized")
|
|
}
|
|
|
|
// Load the agent by ID using the injected function
|
|
agent, err := caller.AgentGetterFunc(agentID)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to load agent %s: %w", agentID, err)
|
|
}
|
|
|
|
// Call the agent with the message
|
|
messages := []agentContext.Message{message}
|
|
|
|
// For A2A calls, skip history and output (we only need the response data)
|
|
opts := &agentContext.Options{Skip: &agentContext.Skip{History: true, Output: true}}
|
|
response, err := agent.Stream(ctx, messages, opts)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to call agent %s: %w", agentID, err)
|
|
}
|
|
|
|
// Extract text from agent response
|
|
return ExtractTextFromResponse(response)
|
|
}
|
|
|
|
// ExtractTextFromResponse extracts text from agent response
|
|
func ExtractTextFromResponse(response *agentContext.Response) (string, error) {
|
|
if response == nil {
|
|
return "", fmt.Errorf("agent returned nil response")
|
|
}
|
|
|
|
// Priority 1: Check Next field (custom hook data)
|
|
if response.Next != nil {
|
|
if nextStr, ok := response.Next.(string); ok {
|
|
return nextStr, nil
|
|
}
|
|
// Otherwise, JSON stringify to preserve complete structure
|
|
jsonBytes, err := jsoniter.Marshal(response.Next)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to serialize next hook data: %w", err)
|
|
}
|
|
return string(jsonBytes), nil
|
|
}
|
|
|
|
// Priority 2: Check Completion field (standard LLM response)
|
|
if response.Completion != nil {
|
|
switch v := response.Completion.Content.(type) {
|
|
case string:
|
|
return v, nil
|
|
case []interface{}:
|
|
// Multimodal content array - extract all text parts
|
|
var text string
|
|
for _, part := range v {
|
|
if partMap, ok := part.(map[string]interface{}); ok {
|
|
if partType, _ := partMap["type"].(string); partType == "text" {
|
|
if textContent, ok := partMap["text"].(string); ok {
|
|
text += textContent
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if text != "" {
|
|
return text, nil
|
|
}
|
|
return "", fmt.Errorf("no text content found in completion content parts")
|
|
}
|
|
}
|
|
|
|
return "", fmt.Errorf("no content found in agent response")
|
|
}
|
|
|
|
// CallMCPTool calls an MCP tool to process content
|
|
func CallMCPTool(ctx *agentContext.Context, serverID string, toolName string, arguments map[string]interface{}) (string, error) {
|
|
// Get MCP context for cancellation/timeout control
|
|
mcpCtx := ctx.Context
|
|
if mcpCtx == nil {
|
|
mcpCtx = context.Background()
|
|
}
|
|
|
|
// Get MCP client
|
|
client, err := mcp.Select(serverID)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to select MCP client '%s': %w", serverID, err)
|
|
}
|
|
|
|
// Call the tool
|
|
log.Trace("[Content] Calling MCP tool: %s (server: %s)", toolName, serverID)
|
|
callResult, err := client.CallTool(mcpCtx, toolName, arguments)
|
|
if err != nil {
|
|
return "", fmt.Errorf("MCP tool call failed: %w", err)
|
|
}
|
|
|
|
// Check if result is an error
|
|
if callResult.IsError {
|
|
return "", fmt.Errorf("MCP tool returned error: %v", callResult.Content)
|
|
}
|
|
|
|
// Extract text content from result
|
|
var text string
|
|
for _, content := range callResult.Content {
|
|
if content.Type == "text" {
|
|
text += content.Text
|
|
}
|
|
}
|
|
|
|
if text == "" {
|
|
return "", fmt.Errorf("MCP tool returned no text content")
|
|
}
|
|
|
|
return text, nil
|
|
}
|