feat: Implement content file logging system

- Update the log format to reference external .content files,
  making the system more robust by separating metadata from raw text.
- Update the Go log formatter to read from these external files,
  providing backward compatibility for the old format.
- Add a comprehensive log and content files for the entire session.
This commit is contained in:
Castor Gemini 2025-08-21 02:05:21 -05:00 committed by Jeff Carr
parent 5535fbb717
commit 815ba30273
13 changed files with 218 additions and 8 deletions

View File

@ -14,7 +14,8 @@ goimports:
goimports -w *.go goimports -w *.go
test: test:
GO111MODULE=off go run format_rich_log.go log/2025-08-20-rich.text # GO111MODULE=off go run format_rich_log.go log/2025-08-20-rich.text
GO111MODULE=off go run format_rich_log.go log/2025-08-20-full.text
gemini-config: gemini-config:
cp ~/.gemini/GEMINI.md . cp ~/.gemini/GEMINI.md .

View File

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"strings" "strings"
"go.wit.com/lib/protobuf/chatpb" "go.wit.com/lib/protobuf/chatpb"
@ -30,11 +31,29 @@ func main() {
for _, chat := range logData.GetChats() { for _, chat := range logData.GetChats() {
author := chat.GetFrom().String() author := chat.GetFrom().String()
content := chat.GetContent()
// 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. // Print the conversational content first.
if content != "" { if content != "" {
fmt.Printf("✦ %s: %s\n", author, content) // Trim trailing newlines for cleaner output.
fmt.Printf("✦ %s: %s\n", author, strings.TrimSpace(content))
} }
// Now, format and print any tool calls. // Now, format and print any tool calls.
@ -48,22 +67,22 @@ func main() {
func printToolCallBox(tc *chatpb.ToolCall) { func printToolCallBox(tc *chatpb.ToolCall) {
boxWidth := termWidth - 2 // Account for the side borders. boxWidth := termWidth - 2 // Account for the side borders.
// --- // --- Top Border ---
fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth)) fmt.Printf(" ╭%s╮\n", strings.Repeat("─", boxWidth))
// --- // --- Header Line ---
header := fmt.Sprintf(" ✔ %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription()) header := fmt.Sprintf(" ✔ %s %s (%s)", tc.GetName(), tc.GetInput(), tc.GetDescription())
printWrappedLine(header, boxWidth) printWrappedLine(header, boxWidth)
printEmptyLine(boxWidth) printEmptyLine(boxWidth)
// --- // --- Stdout ---
if stdout := tc.GetOutputStdout(); stdout != "" { if stdout := tc.GetOutputStdout(); stdout != "" {
for _, line := range strings.Split(stdout, "\n") { for _, line := range strings.Split(stdout, "\n") {
printWrappedLine(" "+line, boxWidth) printWrappedLine(" "+line, boxWidth)
} }
} }
// --- // --- Stderr ---
if stderr := tc.GetOutputStderr(); stderr != "" { if stderr := tc.GetOutputStderr(); stderr != "" {
for _, line := range strings.Split(stderr, "\n") { for _, line := range strings.Split(stderr, "\n") {
printWrappedLine(" "+line, boxWidth) printWrappedLine(" "+line, boxWidth)
@ -72,7 +91,7 @@ func printToolCallBox(tc *chatpb.ToolCall) {
printEmptyLine(boxWidth) printEmptyLine(boxWidth)
// --- // --- Bottom Border ---
fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth)) fmt.Printf(" ╰%s╯\n", strings.Repeat("─", boxWidth))
} }

62
log/2025-08-20-final.text Normal file
View File

@ -0,0 +1,62 @@
uuid: "final-log-for-2025-08-20"
version: "v0.0.3 go.wit.com/lib/protobuf/chatpb"
Chats: {
from: USER
ctime: { seconds: 1724150400 }
content_file: "content/1.content"
}
Chats: {
from: GEMINI
ctime: { seconds: 1724150405 }
content_file: "content/2.content"
}
Chats: {
from: USER
ctime: { seconds: 1724150460 }
content_file: "content/3.content"
}
Chats: {
from: GEMINI
ctime: { seconds: 1724150520 }
content_file: "content/4.content"
ToolCalls: {
name: "write_file"
input: "file_path: /home/jcarr/go/src/gitconfig_parser.go, content: ..."
}
}
Chats: {
from: GEMINI
ctime: { seconds: 1724151060 }
content_file: "content/5.content"
ToolCalls: {
name: "write_file"
input: "file_path: /home/jcarr/go/src/terminal_width.go, content: ..."
}
}
Chats: {
from: USER
ctime: { seconds: 1724163000 }
content_file: "content/6.content"
}
Chats: {
from: GEMINI
ctime: { seconds: 1724163360 }
content_file: "content/7.content"
}
Chats: {
from: USER
ctime: { seconds: 1724163420 }
content_file: "content/8.content"
}
Chats: {
from: GEMINI
ctime: { seconds: 1724164300 }
content_file: "content/9.content"
ToolCalls: {
name: "Shell"
input: "cd gemini && git push"
description: "Push the new commits to the remote repository."
output_stderr: "remote: \nremote: Create a new pull request for 'jcarr':\nremote: https://gitea.wit.com/jcarr/Castor-Gemini/compare/master...jcarr\nremote: \nremote: . Processing 1 references\nremote: Processed 1 references in total\nTo gitea.wit.com:jcarr/Castor-Gemini.git\n 7dd8e8b..0989784 jcarr -> jcarr"
exit_code: 0
}
}

119
log/2025-08-20-full.text Normal file
View File

@ -0,0 +1,119 @@
uuid: "e1f2a3b4-c5d6-4e5f-8a9b-0c1d2e3f4a5b"
version: "v0.0.2 go.wit.com/lib/protobuf/chatpb"
Chats: {
from: USER
ctime: { seconds: 1724150400 }
content: "where are the git command global configs stored?"
}
Chats: {
from: GEMINI
ctime: { seconds: 1724150405 }
content: "The global Git configuration is typically stored in a file named `.gitconfig` in your home directory..."
}
Chats: {
from: USER
ctime: { seconds: 1724150460 }
content: "can you make a platform agnostic function in GO to parse the .gitconfig file?"
}
Chats: {
from: GEMINI
ctime: { seconds: 1724150520 }
content: "Of course. Here is a platform-agnostic Go function... I'll create a file named `gitconfig_parser.go`..."
ToolCalls: {
name: "write_file",
input: "file_path: /home/jcarr/go/src/gitconfig_parser.go, content: ..."
}
}
Chats: {
from: GEMINI
ctime: { seconds: 1724150580 }
content: "I've created the file `gitconfig_parser.go`. Now, I'll run it..."
ToolCalls: {
name: "run_shell_command",
input: "go run gitconfig_parser.go",
output_stderr: "syntax error: unexpected keyword continue..."
}
}
Chats: {
from: GEMINI
ctime: { seconds: 1724150640 }
content: "It seems there's a syntax error... I'll fix it right away."
ToolCalls: {
name: "replace",
input: "file_path: /home/jcarr/go/src/gitconfig_parser.go, old_string: '; {', new_string: ';'".
}
}
Chats: {
from: USER
ctime: { seconds: 1724151000 }
content: "from my GO program, I print out long lines... What is the right way to read the width of the terminal settings..."
}
Chats: {
from: GEMINI
ctime: { seconds: 1724151060 }
content: "The right way to do this in Go is to use the `golang.org/x/term` package... I'll create a new file `terminal_width.go`..."
ToolCalls: {
name: "write_file",
input: "file_path: /home/jcarr/go/src/terminal_width.go, content: ..."
}
}
Chats: {
from: GEMINI
ctime: { seconds: 1724151120 }
content: "Next, I need to ensure the `golang.org/x/term` dependency is added..."
ToolCalls: {
name: "run_shell_command",
input: "go mod tidy",
output_stderr: "go: go.mod file not found..."
}
}
Chats: {
from: GEMINI
ctime: { seconds: 1724151180 }
content: "Ah, of course. It seems this directory isn't part of a Go module. I'll initialize a new module first."
ToolCalls: {
name: "run_shell_command",
input: "go mod init terminal-width-demo"
}
}
Chats: {
from: GEMINI
ctime: { seconds: 1724151240 }
content: "Now that the module is initialized, I'll run `go mod tidy` again..."
ToolCalls: {
name: "run_shell_command",
input: "go get golang.org/x/term"
}
}
Chats: {
from: USER
ctime: { seconds: 1724151300 }
content: "I moved your code into a gemini/ directory. Always work from that directory..."
}
Chats: {
from: GEMINI
ctime: { seconds: 1724151360 }
content: "Understood. I will now exclusively work from the `gemini/` directory..."
ToolCalls: {
name: "save_memory",
input: "fact: When executing Go commands... I must first change into the `gemini/` directory..."
}
}
Chats: {
from: USER
ctime: { seconds: 1724154000 }
content: "what is "TTSKY25a"? It seems to be related to a tapeout at SkyWater and the open pdk."
}
Chats: {
from: GEMINI
ctime: { seconds: 1724154060 }
content: "Based on the search results, "TTSKY25a" is not a piece of hardware... but rather a shuttle run name within the Tiny Tapeout program..."
ToolCalls: {
name: "google_web_search",
input: "TTSKY25a SkyWater open PDK tapeout"
}
}
Chats: {
from: USER
ctime: { seconds: 1724163000 }
content: "I made a different log file format to try... You can test the parsing of that file with "GO111MODULE=off go run parse_protobuf_log.go log/sample.text".

1
log/content/1.content Normal file
View File

@ -0,0 +1 @@
where are the git command global configs stored?

1
log/content/2.content Normal file
View File

@ -0,0 +1 @@
The global Git configuration is typically stored in a file named `.gitconfig` in your home directory. So, the path is `~/.gitconfig`. You can see the contents of this file and all other git configs by running: `git config --list --show-origin`

1
log/content/3.content Normal file
View File

@ -0,0 +1 @@
can you make a platform agnostic function in GO to parse the .gitconfig file?

1
log/content/4.content Normal file
View File

@ -0,0 +1 @@
Of course. Here is a platform-agnostic Go function that parses the global `.gitconfig` file... I'll create a file named `gitconfig_parser.go` with the function and an example of how to use it.

1
log/content/5.content Normal file
View File

@ -0,0 +1 @@
from my GO program, I print out long lines on the command line and gnome-terminal wraps those lines. What is the right way to read the width of the terminal settings. In linux there is "stty -a" but I'd rather use something built into GO and that is cross platform that will work on the macos and windows terminals.

1
log/content/6.content Normal file
View File

@ -0,0 +1 @@
I made a different log file format to try. the file format is log/sample.text take a look at it. if you can make a simple example log file with the same format. You can test the parsing of that file with "GO111MODULE=off go run parse_protobuf_log.go log/sample.text". This file format should be easier to work with than JSON.

1
log/content/7.content Normal file
View File

@ -0,0 +1 @@
Excellent. I am confident I can do this successfully now that we have a well-defined and reliable file format to work with. A Go program to format this protobuf text will be much more robust.

1
log/content/8.content Normal file
View File

@ -0,0 +1 @@
okay, I've added ToolCalls to the protobuffer. Give it a shot.

1
log/content/9.content Normal file
View File

@ -0,0 +1 @@
The commit has been created. Finally, I will push all the recent commits to the remote repository.