Skip to content

Commit df6f34d

Browse files
committed
v0.5.8: kode session trim
New subcommand: kode session trim <id> <n> Keeps the n most recent messages, always preserving the system prompt. Recomputes turn count after trimming. No-op if n >= current message count. Also added to usage and test checks.
1 parent d51b7b2 commit df6f34d

2 files changed

Lines changed: 63 additions & 2 deletions

File tree

cmd/kode/main.go

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func printUsage() {
213213
kode run [flags] <task>
214214
kode run --session [flags] <task>
215215
kode continue [--id <id>] <task>
216-
kode session <list|show [id]|delete <id>>
216+
kode session <list|show [id]|trim <id> <n>|delete <id>>
217217
kode init [--global | -g] [--force | -f]
218218
kode version
219219
@@ -869,8 +869,10 @@ func sessionCmd(args []string) error {
869869
return showSession(store, args[1:])
870870
case "delete":
871871
return deleteSession(store, args[1:])
872+
case "trim":
873+
return trimSession(store, args[1:])
872874
default:
873-
return fmt.Errorf("unknown session command %q (use list, show, delete)", args[0])
875+
return fmt.Errorf("unknown session command %q (use list, show, trim, delete)", args[0])
874876
}
875877
}
876878

@@ -952,6 +954,64 @@ func deleteSession(store *session.Store, args []string) error {
952954
return nil
953955
}
954956

957+
// trimSession keeps only the most recent n messages from a session,
958+
// always preserving the system prompt if present.
959+
// Usage: kode session trim <id> <n>
960+
func trimSession(store *session.Store, args []string) error {
961+
if len(args) < 2 {
962+
return fmt.Errorf("usage: kode session trim <id> <n>")
963+
}
964+
id := args[0]
965+
var n int
966+
if _, err := fmt.Sscanf(args[1], "%d", &n); err != nil || n < 2 {
967+
return fmt.Errorf("n must be at least 2 (system + at least 1 message), got %q", args[1])
968+
}
969+
970+
sess, err := store.Load(id)
971+
if err != nil {
972+
return fmt.Errorf("load session: %w", err)
973+
}
974+
975+
originalLen := len(sess.Messages)
976+
if n >= originalLen {
977+
fmt.Printf("Session %s already has %d messages (≤ %d), nothing to trim.\n", id, originalLen, n)
978+
return nil
979+
}
980+
981+
// Always keep the system message if it's first
982+
hasSystem := len(sess.Messages) > 0 && sess.Messages[0].Role == "system"
983+
984+
if hasSystem {
985+
// Keep system message + last (n-1) messages
986+
keep := n - 1
987+
if keep > len(sess.Messages)-1 {
988+
keep = len(sess.Messages) - 1
989+
}
990+
system := sess.Messages[:1]
991+
tail := sess.Messages[len(sess.Messages)-keep:]
992+
sess.Messages = append(system, tail...)
993+
} else {
994+
// Keep last n messages
995+
sess.Messages = sess.Messages[len(sess.Messages)-n:]
996+
}
997+
998+
// Recompute turn count
999+
sess.Turns = 0
1000+
for _, m := range sess.Messages {
1001+
if m.Role == "user" {
1002+
sess.Turns++
1003+
}
1004+
}
1005+
1006+
if err := store.Save(sess); err != nil {
1007+
return fmt.Errorf("save session: %w", err)
1008+
}
1009+
1010+
dropped := originalLen - len(sess.Messages)
1011+
fmt.Printf("Trimmed session %s: %d → %d messages (%d dropped)\n", id, originalLen, len(sess.Messages), dropped)
1012+
return nil
1013+
}
1014+
9551015
// countUserTurnsUpTo counts user messages up to (but not including) index n.
9561016
func countUserTurnsUpTo(messages []llm.Message, n int) int {
9571017
count := 0

cmd/kode/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ func TestPrintUsage(t *testing.T) {
225225
"kode run",
226226
"kode continue",
227227
"kode session",
228+
"trim",
228229
"kode init",
229230
"kode version",
230231
"Commands:",

0 commit comments

Comments
 (0)