summaryrefslogtreecommitdiff
path: root/format_rich_log.go
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-08-21 12:30:36 -0500
committerJeff Carr <[email protected]>2025-08-21 12:30:36 -0500
commitb221e7a95cc27c8b0b17c7322bea02b88888e033 (patch)
treebde6b41a56167d9f5352e61459c9d7ba4a0e6496 /format_rich_log.go
parente655b37e60a19cbdd1aeddbff0494d74b6a9c5d9 (diff)
add ConfigSave()
Diffstat (limited to 'format_rich_log.go')
-rw-r--r--format_rich_log.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/format_rich_log.go b/format_rich_log.go
new file mode 100644
index 0000000..ddf75bf
--- /dev/null
+++ b/format_rich_log.go
@@ -0,0 +1,112 @@
+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 formatRichLog(filename string) *chatpb.Chats {
+ 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)
+ }
+ }
+
+ return logData
+}
+
+// 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, "")
+}