Castor-Gemini/format_rich_log.go

148 lines
4.1 KiB
Go

package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"go.wit.com/lib/protobuf/chatpb"
"go.wit.com/log"
)
const termWidth = 120 // The target width for the formatted output boxes.
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "Usage: go run format_rich_log.go <path_to_log_file>\n")
os.Exit(1)
}
filename := os.Args[1]
data, err := os.ReadFile(filename)
if err != nil {
log.Fatalf("Error reading file %s: %v", filename, err)
}
logData, err := chatpb.UnmarshalChatsTEXT(data)
if err != nil {
log.Fatalf("Error unmarshaling log file %s: %v", filename, err)
}
for _, chat := range logData.GetChats() {
author := chat.GetFrom().String()
// Handle content: prefer content_file, fallback to content.
var content string
if contentFile := chat.GetContentFile(); contentFile != "" {
// Construct the full path relative to the log file's directory.
logDir := filepath.Dir(filename)
contentPath := filepath.Join(logDir, contentFile)
contentBytes, err := os.ReadFile(contentPath)
if err != nil {
content = fmt.Sprintf("--- ERROR: Could not read content file %s: %v ---", contentPath, err)
} else {
content = string(contentBytes)
}
} else {
// Fallback for older log formats.
content = chat.GetContent()
}
// Print the conversational content first.
if content != "" {
// Trim trailing newlines for cleaner output.
fmt.Printf("✦ %s: %s\n", author, strings.TrimSpace(content))
}
// Now, format and print any tool calls.
for _, toolCall := range chat.GetToolCalls() {
printToolCallBox(toolCall)
}
// Handle the new CodeSnippet field.
if snippets := chat.GetSnippets(); snippets != nil {
logDir := filepath.Dir(filename)
for _, snippet := range snippets {
printCodeSnippet(snippet, logDir)
}
}
}
}
// printCodeSnippet formats a code snippet block by reading its content from a file.
func printCodeSnippet(snippet *chatpb.CodeSnippet, logDir string) {
snippetPath := filepath.Join(logDir, snippet.GetFilename())
codeBytes, err := os.ReadFile(snippetPath)
if err != nil {
fmt.Printf("┌─[ ERROR: Could not read snippet file %s ]─\n\n", snippetPath)
return
}
code := string(codeBytes)
language := filepath.Base(snippet.GetFilename()) // Use the filename as the language for display
fmt.Printf("┌─[ Code Snippet: %s ]──────────────────────────────────\n", language)
// Print each line of the code indented.
for _, line := range strings.Split(strings.TrimSpace(code), "\n") {
fmt.Printf("│ %s\n", line)
}
fmt.Printf("└─────────────────────────────────────────────────────────\n\n")
}
// printToolCallBox handles the decorative formatting for a single tool call.
func printToolCallBox(tc *chatpb.ToolCall) {
boxWidth := termWidth - 2 // Account for the side borders.
// --- Top Border ---
fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth))
// --- Header Line ---
header := fmt.Sprintf(" ✔ %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription())
printWrappedLine(header, boxWidth)
printEmptyLine(boxWidth)
// --- Stdout ---
if stdout := tc.GetOutputStdout(); stdout != "" {
for _, line := range strings.Split(stdout, "\n") {
printWrappedLine(" "+line, boxWidth)
}
}
// --- Stderr ---
if stderr := tc.GetOutputStderr(); stderr != "" {
for _, line := range strings.Split(stderr, "\n") {
printWrappedLine(" "+line, boxWidth)
}
}
printEmptyLine(boxWidth)
// --- Bottom Border ---
fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth))
}
// printWrappedLine prints a line of text, wrapping it if it's too long.
func printWrappedLine(text string, width int) {
if len(text) == 0 {
printEmptyLine(width)
return
}
// Simple wrapping logic.
for len(text) > width {
fmt.Printf(" │ %-*s │\n", width, text[:width])
text = text[width:]
}
fmt.Printf(" │ %-*s │\n", width, text)
}
// printEmptyLine prints a blank line within the box.
func printEmptyLine(width int) {
fmt.Printf(" │ %*s │\n", width, "")
}