diff options
| author | Grail Finder <wohilas@gmail.com> | 2025-12-18 11:53:07 +0300 |
|---|---|---|
| committer | Grail Finder <wohilas@gmail.com> | 2025-12-18 11:53:07 +0300 |
| commit | a06cfd995f05782854844e51a71a656f70274f64 (patch) | |
| tree | 8550a63a928771c758ac051f23ac12613d053f27 /agent/format.go | |
| parent | d73c3abd6bda8690e8b5e57342221c8cb2cc88b3 (diff) | |
Feat: add agent entity
Diffstat (limited to 'agent/format.go')
| -rw-r--r-- | agent/format.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/agent/format.go b/agent/format.go new file mode 100644 index 0000000..01ecb07 --- /dev/null +++ b/agent/format.go @@ -0,0 +1,120 @@ +package agent + +import ( + "encoding/json" + "fmt" + "strings" +) + +// FormatSearchResults takes raw JSON from websearch and returns a concise summary. +func FormatSearchResults(rawJSON []byte) (string, error) { + // Try to unmarshal as generic slice of maps + var results []map[string]interface{} + if err := json.Unmarshal(rawJSON, &results); err != nil { + // If that fails, try as a single map (maybe wrapper object) + var wrapper map[string]interface{} + if err2 := json.Unmarshal(rawJSON, &wrapper); err2 == nil { + // Look for a "results" or "data" field + if data, ok := wrapper["results"].([]interface{}); ok { + // Convert to slice of maps + for _, item := range data { + if m, ok := item.(map[string]interface{}); ok { + results = append(results, m) + } + } + } else if data, ok := wrapper["data"].([]interface{}); ok { + for _, item := range data { + if m, ok := item.(map[string]interface{}); ok { + results = append(results, m) + } + } + } else { + // No slice found, treat wrapper as single result + results = []map[string]interface{}{wrapper} + } + } else { + return "", fmt.Errorf("failed to unmarshal search results: %v (also %v)", err, err2) + } + } + + if len(results) == 0 { + return "No search results found.", nil + } + + var sb strings.Builder + sb.WriteString(fmt.Sprintf("Found %d results:\n", len(results))) + for i, r := range results { + // Extract common fields + title := getString(r, "title", "Title", "name", "heading") + snippet := getString(r, "snippet", "description", "content", "body", "text", "summary") + url := getString(r, "url", "link", "uri", "source") + + sb.WriteString(fmt.Sprintf("%d. ", i+1)) + if title != "" { + sb.WriteString(fmt.Sprintf("**%s**", title)) + } else { + sb.WriteString("(No title)") + } + if snippet != "" { + // Truncate snippet to reasonable length + if len(snippet) > 200 { + snippet = snippet[:200] + "..." + } + sb.WriteString(fmt.Sprintf(" — %s", snippet)) + } + if url != "" { + sb.WriteString(fmt.Sprintf(" (%s)", url)) + } + sb.WriteString("\n") + } + return sb.String(), nil +} + +// FormatWebPageContent takes raw JSON from read_url and returns a concise summary. +func FormatWebPageContent(rawJSON []byte) (string, error) { + // Try to unmarshal as generic map + var data map[string]interface{} + if err := json.Unmarshal(rawJSON, &data); err != nil { + // If that fails, try as string directly + var content string + if err2 := json.Unmarshal(rawJSON, &content); err2 == nil { + return truncateText(content, 500), nil + } + // Both failed, return first error + return "", fmt.Errorf("failed to unmarshal web page content: %v", err) + } + + // Look for common content fields + content := getString(data, "content", "text", "body", "article", "html", "markdown", "data") + if content == "" { + // If no content field, marshal the whole thing as a short string + summary := fmt.Sprintf("%v", data) + return truncateText(summary, 300), nil + } + return truncateText(content, 500), nil +} + +// Helper to get a string value from a map, trying multiple keys. +func getString(m map[string]interface{}, keys ...string) string { + for _, k := range keys { + if val, ok := m[k]; ok { + switch v := val.(type) { + case string: + return v + case fmt.Stringer: + return v.String() + default: + return fmt.Sprintf("%v", v) + } + } + } + return "" +} + +// Helper to truncate text and add ellipsis. +func truncateText(s string, maxLen int) string { + if len(s) <= maxLen { + return s + } + return s[:maxLen] + "..." +}
\ No newline at end of file |
