| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "os" |
| 5 | "path/filepath" |
| 6 | "reasonix/internal/agent" |
| 7 | "reasonix/internal/control" |
| 8 | "reasonix/internal/provider" |
| 9 | "testing" |
| 10 | ) |
| 11 | |
| 12 | func TestOpenTopicTabKeepsRunningParentInsteadOfCoveringLeaf(t *testing.T) { |
| 13 | isolateDesktopUserDirs(t) |
| 14 | dir := desktopSessionDir(globalWorkspaceRoot()) |
| 15 | if err := os.MkdirAll(dir, 0o755); err != nil { |
| 16 | t.Fatal(err) |
| 17 | } |
| 18 | q := provider.Message{Role: provider.RoleUser, Content: "question"} |
| 19 | a := provider.Message{Role: provider.RoleAssistant, Content: "answer"} |
| 20 | save := func(path, topic string, messages ...provider.Message) { |
| 21 | t.Helper() |
| 22 | session := agent.NewSession("sys") |
| 23 | for _, message := range messages { |
| 24 | session.Add(message) |
| 25 | } |
| 26 | if err := session.Save(path); err != nil { |
| 27 | t.Fatal(err) |
| 28 | } |
| 29 | if err := agent.SaveBranchMetaPreserveUpdated(path, agent.BranchMeta{ |
| 30 | ID: agent.BranchID(path), Scope: "global", TopicID: topic, TopicTitle: "Upgraded", |
| 31 | }); err != nil { |
| 32 | t.Fatal(err) |
| 33 | } |
| 34 | } |
| 35 | root := filepath.Join(dir, "root.jsonl") |
| 36 | leaf := filepath.Join(dir, "leaf.jsonl") |
| 37 | save(root, "conversation", q, a) |
| 38 | save(leaf, "legacy-leaf-topic", q, a, |
| 39 | provider.Message{Role: provider.RoleUser, Content: "next"}, |
| 40 | provider.Message{Role: provider.RoleAssistant, Content: "done"}) |
| 41 | if err := agent.SaveBranchMetaPreserveUpdated(leaf, agent.BranchMeta{ |
| 42 | ID: "leaf", Scope: "global", TopicID: "legacy-leaf-topic", |
| 43 | Recovered: true, ParentID: "root", RecoveryDepth: 1, |
| 44 | }); err != nil { |
| 45 | t.Fatal(err) |
| 46 | } |
| 47 | app := NewApp() |
| 48 | installSessionCatalogForTest(t, app, dir, "global", "") |
| 49 | running := &WorkspaceTab{ |
| 50 | ID: "running", Scope: "global", TopicID: "conversation", SessionPath: root, |
| 51 | Ctrl: &retargetRuntimeController{status: control.RuntimeStatus{Running: true}, path: root}, |
| 52 | } |
| 53 | app.tabs = map[string]*WorkspaceTab{"running": running} |
| 54 | |
| 55 | _, resolved := app.resolveOpenTopicSessionPath("global", "", root) |
| 56 | if resolved != root { |
| 57 | t.Fatalf("resolve running open = %q, want parent %q", resolved, root) |
| 58 | } |
| 59 | |
| 60 | meta, err := app.openTopicTab("global", "", "conversation", root) |
| 61 | if err != nil { |
| 62 | t.Fatal(err) |
| 63 | } |
| 64 | if running.SessionPath != root { |
| 65 | t.Fatalf("running tab path = %q, want parent %q", running.SessionPath, root) |
| 66 | } |
| 67 | if meta.ID != "running" || meta.SessionPath != root { |
| 68 | t.Fatalf("open meta = %+v, want focused running parent", meta) |
| 69 | } |
| 70 | |
| 71 | idle := &WorkspaceTab{ID: "idle", Scope: "global", TopicID: "conversation", SessionPath: root} |
| 72 | app.tabs = map[string]*WorkspaceTab{"idle": idle} |
| 73 | _, idleResolved := app.resolveOpenTopicSessionPath("global", "", root) |
| 74 | if idleResolved != leaf { |
| 75 | t.Fatalf("resolve idle open = %q, want covering leaf %q", idleResolved, leaf) |
| 76 | } |
| 77 | } |
| 78 |