Skip to content

Commit fdc239a

Browse files
author
Test
committed
Implement lifetime savings badge and gain share flag
Before this commit, there was no centralized helper to calculate lifetime token and financial savings in the CLI. Furthermore, the REPL shell prompt only showed the Caveman Mode level (lacking visual feedback on cumulative performance gains), and there was no way to export or share a single-line summary of token optimization benefits. We implemented a centralized GetLifetimeSavings() helper inside internal/observability/observer.go which parses the local savings logs. We then integrated this helper into internal/repl/chat_repl.go to display a lifetime savings badge (e.g. ⛏12.4k) directly inside the readline prompt next to the Caveman level. Finally, we added a --share flag to gptcode gain to output a single-line tweetable optimization summary (inspired by caveman-stats). An ideal solution would support automatic sharing integration (e.g., opening a browser window to Twitter/X with pre-filled tweet text) and cache lifetime metrics in memory to avoid parsing the savings JSONL file on every prompt render.
1 parent eae1eb8 commit fdc239a

3 files changed

Lines changed: 66 additions & 1 deletion

File tree

cmd/gptcode/gain.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ type SavingsRecord struct {
1919
CostSaved float64 `json:"cost_saved"`
2020
}
2121

22+
var shareFlag bool
23+
2224
var gainCmd = &cobra.Command{
2325
Use: "gain",
2426
Short: "Show cumulative token and cost savings from command optimization",
@@ -74,6 +76,19 @@ and count of commands optimized by the GPTCode output filtering engine (adapted
7476
return err
7577
}
7678

79+
if shareFlag {
80+
savingsStr := ""
81+
if totalTokensSaved >= 1000000 {
82+
savingsStr = fmt.Sprintf("%.1fM", float64(totalTokensSaved)/1000000.0)
83+
} else if totalTokensSaved >= 1000 {
84+
savingsStr = fmt.Sprintf("%.1fk", float64(totalTokensSaved)/1000.0)
85+
} else {
86+
savingsStr = fmt.Sprintf("%d", totalTokensSaved)
87+
}
88+
fmt.Printf("⛏ saved %s tokens ($%.4f) using @gptcode token optimization! why use many token when few do trick\n", savingsStr, totalCostSaved)
89+
return nil
90+
}
91+
7792
fmt.Println("============================================================")
7893
fmt.Println(" GPTCode Token Savings Report")
7994
fmt.Println("============================================================")
@@ -94,3 +109,7 @@ and count of commands optimized by the GPTCode output filtering engine (adapted
94109
return nil
95110
},
96111
}
112+
113+
func init() {
114+
gainCmd.Flags().BoolVarP(&shareFlag, "share", "s", false, "Print a shareable/tweetable savings badge line")
115+
}

internal/observability/observer.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package observability
22

33
import (
4+
"bufio"
45
"encoding/json"
56
"fmt"
67
"os"
@@ -604,3 +605,32 @@ func (o *AgentObserver) recordSavingsToDisk(toolName string, tokensSaved int, co
604605

605606
_, _ = f.Write(append(data, '\n'))
606607
}
608+
609+
// GetLifetimeSavings parses the savings file and aggregates tokens and cost saved
610+
func GetLifetimeSavings() (int, float64, error) {
611+
home, err := os.UserHomeDir()
612+
if err != nil {
613+
return 0, 0, err
614+
}
615+
savingsFile := filepath.Join(home, ".gptcode", "savings.jsonl")
616+
file, err := os.Open(savingsFile)
617+
if err != nil {
618+
if os.IsNotExist(err) {
619+
return 0, 0, nil
620+
}
621+
return 0, 0, err
622+
}
623+
defer file.Close()
624+
625+
var totalTokens int
626+
var totalCost float64
627+
scanner := bufio.NewScanner(file)
628+
for scanner.Scan() {
629+
var record SavingsRecord
630+
if err := json.Unmarshal([]byte(scanner.Text()), &record); err == nil {
631+
totalTokens += record.TokensSaved
632+
totalCost += record.CostSaved
633+
}
634+
}
635+
return totalTokens, totalCost, scanner.Err()
636+
}

internal/repl/chat_repl.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"gptcode/internal/config"
1212
"gptcode/internal/llm"
1313
"gptcode/internal/modes"
14+
"gptcode/internal/observability"
1415
"gptcode/internal/prompt"
1516
)
1617

@@ -411,8 +412,23 @@ func RunSingleShot(input string, args []string) error {
411412
func (r *ChatREPL) updatePrompt() {
412413
setup, err := config.LoadSetup()
413414
promptStr := "> "
415+
416+
// Try loading lifetime savings
417+
savingsStr := ""
418+
if tokens, _, err := observability.GetLifetimeSavings(); err == nil && tokens > 0 {
419+
if tokens >= 1000000 {
420+
savingsStr = fmt.Sprintf(" | ⛏%.1fM", float64(tokens)/1000000.0)
421+
} else if tokens >= 1000 {
422+
savingsStr = fmt.Sprintf(" | ⛏%.1fk", float64(tokens)/1000.0)
423+
} else {
424+
savingsStr = fmt.Sprintf(" | ⛏%d", tokens)
425+
}
426+
}
427+
414428
if err == nil && setup.Defaults.CavemanMode != "" && setup.Defaults.CavemanMode != "off" {
415-
promptStr = fmt.Sprintf("(caveman:%s) > ", setup.Defaults.CavemanMode)
429+
promptStr = fmt.Sprintf("(caveman:%s%s) > ", setup.Defaults.CavemanMode, savingsStr)
430+
} else if savingsStr != "" {
431+
promptStr = fmt.Sprintf("(%s) > ", strings.TrimPrefix(savingsStr, " | "))
416432
}
417433
r.rl.SetPrompt(promptStr)
418434
}

0 commit comments

Comments
 (0)