@@ -3,6 +3,8 @@ package tools
5 "encoding/json"
5 "encoding/json"
8type ToolInfo struct {
10type ToolInfo struct {
@@ -25,6 +27,10 @@ const (
26 SessionIDContextKey sessionIDContextKey = "session_id"
28 SessionIDContextKey sessionIDContextKey = "session_id"
27 MessageIDContextKey messageIDContextKey = "message_id"
29 MessageIDContextKey messageIDContextKey = "message_id"
31+ maxResponseWidth = 3000
32+ maxResponseHeight = 5000
33+ maxResponseChars = 50000
30type ToolResponse struct {
36type ToolResponse struct {
@@ -37,10 +43,77 @@ type ToolResponse struct {
37func NewTextResponse(content string) ToolResponse {
43func NewTextResponse(content string) ToolResponse {
38 return ToolResponse{
44 return ToolResponse{
39 Type: ToolResponseTypeText,
45 Type: ToolResponseTypeText,
40− Content: content,
46+ Content: truncateContent(content),
50+func truncateContent(content string) string {
51+ if len(content) <= maxResponseChars {
52+ return truncateWidthAndHeight(content)
55+ truncated := content[:maxResponseChars]
57+ if lastNewline := strings.LastIndex(truncated, "\n"); lastNewline > maxResponseChars/2 {
58+ truncated = truncated[:lastNewline]
61+ truncated += "\n\n... [Content truncated due to length] ..."
63+ return truncateWidthAndHeight(truncated)
66+func truncateWidthAndHeight(content string) string {
67+ lines := strings.Split(content, "\n")
69+ heightTruncated := false
70+ if len(lines) > maxResponseHeight {
71+ keepLines := maxResponseHeight - 3
72+ firstHalf := keepLines / 2
73+ secondHalf := keepLines - firstHalf
75+ truncatedLines := make([]string, 0, maxResponseHeight)
76+ truncatedLines = append(truncatedLines, lines[:firstHalf]...)
77+ truncatedLines = append(truncatedLines, "")
78+ truncatedLines = append(truncatedLines, fmt.Sprintf("... [%d lines truncated] ...", len(lines)-keepLines))
79+ truncatedLines = append(truncatedLines, "")
80+ truncatedLines = append(truncatedLines, lines[len(lines)-secondHalf:]...)
82+ lines = truncatedLines
83+ heightTruncated = true
86+ widthTruncated := false
87+ for i, line := range lines {
88+ if len(line) > maxResponseWidth {
89+ if maxResponseWidth > 20 {
90+ keepChars := maxResponseWidth - 10
91+ firstHalf := keepChars / 2
92+ secondHalf := keepChars - firstHalf
93+ lines[i] = line[:firstHalf] + " ... " + line[len(line)-secondHalf:]
95+ lines[i] = line[:maxResponseWidth]
97+ widthTruncated = true
101+ result := strings.Join(lines, "\n")
103+ if heightTruncated || widthTruncated {
104+ notices := make([]string, 0, 2)
105+ if heightTruncated {
106+ notices = append(notices, "height")
109+ notices = append(notices, "width")
111+ result += fmt.Sprintf("\n\n[Note: Content truncated by %s to fit response limits]", strings.Join(notices, " and "))
44func WithResponseMetadata(response ToolResponse, metadata any) ToolResponse {
117func WithResponseMetadata(response ToolResponse, metadata any) ToolResponse {
45 if metadata != nil {
118 if metadata != nil {
46 metadataBytes, err := json.Marshal(metadata)
119 metadataBytes, err := json.Marshal(metadata)