mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(reasoning): persist canonical history for DeepSeek and web chat
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/fileutil"
|
||||
"github.com/sipeed/picoclaw/pkg/providers"
|
||||
"github.com/sipeed/picoclaw/pkg/providers/messageutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -482,6 +483,9 @@ func readMessages(path string, skip int) ([]providers.Message, error) {
|
||||
lineNum, filepath.Base(path), err)
|
||||
continue
|
||||
}
|
||||
if messageutil.IsTransientAssistantThoughtMessage(msg) {
|
||||
continue
|
||||
}
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
@@ -535,6 +539,10 @@ func (s *JSONLStore) AddFullMessage(
|
||||
|
||||
// addMsg is the shared implementation for AddMessage and AddFullMessage.
|
||||
func (s *JSONLStore) addMsg(sessionKey string, msg providers.Message) error {
|
||||
if messageutil.IsTransientAssistantThoughtMessage(msg) {
|
||||
return nil
|
||||
}
|
||||
|
||||
l := s.sessionLock(sessionKey)
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
@@ -684,6 +692,8 @@ func (s *JSONLStore) SetHistory(
|
||||
sessionKey string,
|
||||
history []providers.Message,
|
||||
) error {
|
||||
history = messageutil.FilterInvalidHistoryMessages(history)
|
||||
|
||||
l := s.sessionLock(sessionKey)
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
@@ -762,6 +772,8 @@ func (s *JSONLStore) Compact(
|
||||
func (s *JSONLStore) rewriteJSONL(
|
||||
sessionKey string, msgs []providers.Message,
|
||||
) error {
|
||||
msgs = messageutil.FilterInvalidHistoryMessages(msgs)
|
||||
|
||||
var buf bytes.Buffer
|
||||
for i, msg := range msgs {
|
||||
line, err := json.Marshal(msg)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -155,6 +156,27 @@ func TestAddFullMessage_ToolCallID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddFullMessage_DropsTransientAssistantThought(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
err := store.AddFullMessage(ctx, "transient-thought", providers.Message{
|
||||
Role: "assistant",
|
||||
ReasoningContent: "internal chain of thought",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("AddFullMessage: %v", err)
|
||||
}
|
||||
|
||||
history, err := store.GetHistory(ctx, "transient-thought")
|
||||
if err != nil {
|
||||
t.Fatalf("GetHistory: %v", err)
|
||||
}
|
||||
if len(history) != 0 {
|
||||
t.Fatalf("expected transient thought to be discarded, got %d messages", len(history))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistory_EmptySession(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
@@ -243,6 +265,46 @@ func TestSetSummary_GetSummary(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetHistory_DropsTransientAssistantThought(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
newHistory := []providers.Message{
|
||||
{Role: "user", Content: "hello"},
|
||||
{Role: "assistant", ReasoningContent: "internal chain of thought"},
|
||||
{Role: "assistant", Content: "visible answer", ReasoningContent: "visible thought"},
|
||||
}
|
||||
|
||||
err := store.SetHistory(ctx, "replace", newHistory)
|
||||
if err != nil {
|
||||
t.Fatalf("SetHistory: %v", err)
|
||||
}
|
||||
|
||||
history, err := store.GetHistory(ctx, "replace")
|
||||
if err != nil {
|
||||
t.Fatalf("GetHistory: %v", err)
|
||||
}
|
||||
if len(history) != 2 {
|
||||
t.Fatalf("expected transient thought to be removed, got %d messages", len(history))
|
||||
}
|
||||
if history[0].Role != "user" || history[0].Content != "hello" {
|
||||
t.Fatalf("history[0] = %+v, want user/hello", history[0])
|
||||
}
|
||||
if history[1].Role != "assistant" || history[1].Content != "visible answer" ||
|
||||
history[1].ReasoningContent != "visible thought" {
|
||||
t.Fatalf("history[1] = %+v, want assistant visible answer with reasoning", history[1])
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(store.jsonlPath("replace"))
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile(jsonl): %v", err)
|
||||
}
|
||||
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
|
||||
if len(lines) != 2 {
|
||||
t.Fatalf("jsonl line count = %d, want 2", len(lines))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionMetaScopeAndAliasesPersist(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
Reference in New Issue
Block a user