023f224d51
- Deleted tool_filter_middleware_test.go and tool_helpers.go as they are no longer needed. - Removed associated test cases in tool_helpers_test.go. - Refactored knowledge retriever logic by moving it to a new file and updating imports. - Introduced tooling package for tool result reduction logic. - Updated traces package to include new trace types and structures. - Adjusted executor and tool search tool to reflect new package structure.
103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
package tooling
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"agent-desk/internal/ai/mcps"
|
|
)
|
|
|
|
const (
|
|
maxToolResultSummaryChars = 4000
|
|
maxToolResultSegments = 12
|
|
)
|
|
|
|
var reductionInfoPattern = regexp.MustCompile(`\[tool result reduced: original_length=(\d+), kept_length=(\d+)\]`)
|
|
|
|
type ReductionInfo struct {
|
|
Reduced bool
|
|
OriginalChars int
|
|
KeptChars int
|
|
}
|
|
|
|
// BuildReducedToolResultSummary returns a bounded text summary for MCP tool results.
|
|
// It keeps the main payload visible to the model while preventing a single large tool
|
|
// response from exhausting too much context.
|
|
func BuildReducedToolResultSummary(result *mcps.ToolCallResult) string {
|
|
if result == nil {
|
|
return ""
|
|
}
|
|
segments := collectToolResultSegments(result)
|
|
if len(segments) == 0 {
|
|
return ""
|
|
}
|
|
text := strings.TrimSpace(strings.Join(segments, "\n"))
|
|
if text == "" {
|
|
return ""
|
|
}
|
|
runes := []rune(text)
|
|
if len(runes) <= maxToolResultSummaryChars {
|
|
return text
|
|
}
|
|
truncated := strings.TrimSpace(string(runes[:maxToolResultSummaryChars]))
|
|
return fmt.Sprintf("%s\n\n[tool result reduced: original_length=%d, kept_length=%d]", truncated, len(runes), maxToolResultSummaryChars)
|
|
}
|
|
|
|
func ParseReductionInfo(summary string) ReductionInfo {
|
|
matches := reductionInfoPattern.FindStringSubmatch(strings.TrimSpace(summary))
|
|
if len(matches) != 3 {
|
|
return ReductionInfo{}
|
|
}
|
|
originalChars, err1 := strconv.Atoi(matches[1])
|
|
keptChars, err2 := strconv.Atoi(matches[2])
|
|
if err1 != nil || err2 != nil {
|
|
return ReductionInfo{}
|
|
}
|
|
return ReductionInfo{
|
|
Reduced: true,
|
|
OriginalChars: originalChars,
|
|
KeptChars: keptChars,
|
|
}
|
|
}
|
|
|
|
func collectToolResultSegments(result *mcps.ToolCallResult) []string {
|
|
segments := make([]string, 0, len(result.Content)+2)
|
|
if result.IsError {
|
|
segments = append(segments, "tool returned an error")
|
|
}
|
|
if result.StructuredContent != nil {
|
|
if data, err := json.Marshal(result.StructuredContent); err == nil {
|
|
segments = appendNonBlankSegment(segments, string(data))
|
|
}
|
|
}
|
|
for _, item := range result.Content {
|
|
if len(segments) >= maxToolResultSegments {
|
|
segments = append(segments, "[tool result reduced: remaining segments omitted]")
|
|
break
|
|
}
|
|
switch item.Type {
|
|
case "text":
|
|
segments = appendNonBlankSegment(segments, item.Text)
|
|
default:
|
|
if item.Data == nil {
|
|
continue
|
|
}
|
|
if data, err := json.Marshal(item.Data); err == nil {
|
|
segments = appendNonBlankSegment(segments, string(data))
|
|
}
|
|
}
|
|
}
|
|
return segments
|
|
}
|
|
|
|
func appendNonBlankSegment(input []string, value string) []string {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return input
|
|
}
|
|
return append(input, value)
|
|
}
|