mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(session): restore thread and legacy compatibility
This commit is contained in:
@@ -256,11 +256,13 @@ func (h *Handler) findPicoJSONLSessions(dir string) ([]picoJSONLSessionRef, erro
|
||||
|
||||
refs := make([]picoJSONLSessionRef, 0)
|
||||
seen := make(map[string]struct{})
|
||||
metaBackedBases := make(map[string]struct{})
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".meta.json") {
|
||||
continue
|
||||
}
|
||||
metaPath := filepath.Join(dir, entry.Name())
|
||||
name := entry.Name()
|
||||
metaPath := filepath.Join(dir, name)
|
||||
meta, err := h.readSessionMeta(metaPath, "")
|
||||
if err != nil {
|
||||
continue
|
||||
@@ -269,6 +271,27 @@ func (h *Handler) findPicoJSONLSessions(dir string) ([]picoJSONLSessionRef, erro
|
||||
if !ok || ref.Key == "" || ref.ID == "" {
|
||||
continue
|
||||
}
|
||||
metaBackedBases[strings.TrimSuffix(name, ".meta.json")] = struct{}{}
|
||||
if _, exists := seen[ref.ID]; exists {
|
||||
continue
|
||||
}
|
||||
seen[ref.ID] = struct{}{}
|
||||
refs = append(refs, ref)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".jsonl") {
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
base := strings.TrimSuffix(name, ".jsonl")
|
||||
if _, ok := metaBackedBases[base]; ok {
|
||||
continue
|
||||
}
|
||||
ref, ok := jsonlSessionRefFromFilename(name)
|
||||
if !ok || ref.Key == "" || ref.ID == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[ref.ID]; exists {
|
||||
continue
|
||||
}
|
||||
@@ -300,7 +323,8 @@ func (h *Handler) findLegacyPicoSessions(dir string) ([]picoLegacySessionRef, er
|
||||
refs := make([]picoLegacySessionRef, 0)
|
||||
seen := make(map[string]struct{})
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || filepath.Ext(entry.Name()) != ".json" {
|
||||
name := entry.Name()
|
||||
if entry.IsDir() || filepath.Ext(name) != ".json" || strings.HasSuffix(name, ".meta.json") {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -323,6 +347,37 @@ func (h *Handler) findLegacyPicoSessions(dir string) ([]picoLegacySessionRef, er
|
||||
return refs, nil
|
||||
}
|
||||
|
||||
func jsonlSessionRefFromFilename(name string) (picoJSONLSessionRef, bool) {
|
||||
if !strings.HasSuffix(name, ".jsonl") {
|
||||
return picoJSONLSessionRef{}, false
|
||||
}
|
||||
base := strings.TrimSuffix(name, ".jsonl")
|
||||
if base == "" {
|
||||
return picoJSONLSessionRef{}, false
|
||||
}
|
||||
|
||||
legacyPrefix := sanitizeSessionKey(legacyPicoSessionPrefix)
|
||||
if strings.HasPrefix(base, legacyPrefix) {
|
||||
sessionID := strings.TrimPrefix(base, legacyPrefix)
|
||||
if sessionID == "" {
|
||||
return picoJSONLSessionRef{}, false
|
||||
}
|
||||
return picoJSONLSessionRef{
|
||||
ID: sessionID,
|
||||
Key: legacyPicoSessionPrefix + sessionID,
|
||||
}, true
|
||||
}
|
||||
|
||||
if session.IsOpaqueSessionKey(base) {
|
||||
return picoJSONLSessionRef{
|
||||
ID: base,
|
||||
Key: base,
|
||||
}, true
|
||||
}
|
||||
|
||||
return picoJSONLSessionRef{}, false
|
||||
}
|
||||
|
||||
func (h *Handler) findLegacyPicoSession(dir, sessionID string) (picoLegacySessionRef, error) {
|
||||
refs, err := h.findLegacyPicoSessions(dir)
|
||||
if err != nil {
|
||||
|
||||
@@ -750,3 +750,82 @@ func TestHandleSessions_FiltersEmptyJSONLFiles(t *testing.T) {
|
||||
t.Fatalf("detail status = %d, want %d, body=%s", detailRec.Code, http.StatusNotFound, detailRec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleSessions_ListsLegacyJSONLWithoutMeta(t *testing.T) {
|
||||
configPath, cleanup := setupOAuthTestEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
dir := sessionsTestDir(t, configPath)
|
||||
sessionKey := legacyPicoSessionPrefix + "missing-meta"
|
||||
base := filepath.Join(dir, sanitizeSessionKey(sessionKey))
|
||||
line, err := json.Marshal(providers.Message{Role: "user", Content: "recover me"})
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal(message) error = %v", err)
|
||||
}
|
||||
if err := os.WriteFile(base+".jsonl", append(line, '\n'), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile(jsonl) error = %v", err)
|
||||
}
|
||||
|
||||
h := NewHandler(configPath)
|
||||
mux := http.NewServeMux()
|
||||
h.RegisterRoutes(mux)
|
||||
|
||||
listRec := httptest.NewRecorder()
|
||||
listReq := httptest.NewRequest(http.MethodGet, "/api/sessions", nil)
|
||||
mux.ServeHTTP(listRec, listReq)
|
||||
|
||||
if listRec.Code != http.StatusOK {
|
||||
t.Fatalf("list status = %d, want %d, body=%s", listRec.Code, http.StatusOK, listRec.Body.String())
|
||||
}
|
||||
|
||||
var items []sessionListItem
|
||||
if err := json.Unmarshal(listRec.Body.Bytes(), &items); err != nil {
|
||||
t.Fatalf("Unmarshal(list) error = %v", err)
|
||||
}
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("len(items) = %d, want 1", len(items))
|
||||
}
|
||||
if items[0].ID != "missing-meta" {
|
||||
t.Fatalf("items[0].ID = %q, want %q", items[0].ID, "missing-meta")
|
||||
}
|
||||
|
||||
detailRec := httptest.NewRecorder()
|
||||
detailReq := httptest.NewRequest(http.MethodGet, "/api/sessions/missing-meta", nil)
|
||||
mux.ServeHTTP(detailRec, detailReq)
|
||||
|
||||
if detailRec.Code != http.StatusOK {
|
||||
t.Fatalf("detail status = %d, want %d, body=%s", detailRec.Code, http.StatusOK, detailRec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleSessions_IgnoresMetaJSONInLegacyFallback(t *testing.T) {
|
||||
configPath, cleanup := setupOAuthTestEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
dir := sessionsTestDir(t, configPath)
|
||||
metaOnly := filepath.Join(dir, "agent_main_pico_direct_pico_meta-only.meta.json")
|
||||
metaOnlyContent := []byte(`{"key":"agent:main:pico:direct:pico:meta-only","summary":"meta only"}`)
|
||||
if err := os.WriteFile(metaOnly, metaOnlyContent, 0o644); err != nil {
|
||||
t.Fatalf("WriteFile(meta) error = %v", err)
|
||||
}
|
||||
|
||||
h := NewHandler(configPath)
|
||||
mux := http.NewServeMux()
|
||||
h.RegisterRoutes(mux)
|
||||
|
||||
listRec := httptest.NewRecorder()
|
||||
listReq := httptest.NewRequest(http.MethodGet, "/api/sessions", nil)
|
||||
mux.ServeHTTP(listRec, listReq)
|
||||
|
||||
if listRec.Code != http.StatusOK {
|
||||
t.Fatalf("list status = %d, want %d, body=%s", listRec.Code, http.StatusOK, listRec.Body.String())
|
||||
}
|
||||
|
||||
var items []sessionListItem
|
||||
if err := json.Unmarshal(listRec.Body.Bytes(), &items); err != nil {
|
||||
t.Fatalf("Unmarshal(list) error = %v", err)
|
||||
}
|
||||
if len(items) != 0 {
|
||||
t.Fatalf("len(items) = %d, want 0", len(items))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user