-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathcodex_model_test.go
More file actions
144 lines (134 loc) · 4.31 KB
/
Copy pathcodex_model_test.go
File metadata and controls
144 lines (134 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package adapter
import (
"bufio"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
)
// writeCodexRollout creates a Codex CLI rollout JSONL file under
// CODEX_HOME/sessions/2026/07/25/rollout-<timestamp>-<thread>.jsonl and writes
// the given raw lines (one JSON record per line). It returns the file path.
func writeCodexRollout(t *testing.T, codexHome, thread, timestamp string, lines []string) string {
t.Helper()
dir := filepath.Join(codexHome, "sessions", "2026", "07", "25")
if err := os.MkdirAll(dir, 0o755); err != nil {
t.Fatalf("mkdir rollout dir: %v", err)
}
path := filepath.Join(dir, fmt.Sprintf("rollout-%s-%s.jsonl", timestamp, thread))
f, err := os.Create(path)
if err != nil {
t.Fatalf("create rollout: %v", err)
}
defer f.Close()
w := bufio.NewWriter(f)
for _, l := range lines {
if _, err := w.WriteString(l + "\n"); err != nil {
t.Fatalf("write rollout line: %v", err)
}
}
if err := w.Flush(); err != nil {
t.Fatalf("flush rollout: %v", err)
}
return path
}
// turnContextLine returns a JSONL record for a Codex turn_context entry with
// the given turn_id and model.
func turnContextLine(turnID, model string) string {
rec := map[string]interface{}{
"type": "turn_context",
"payload": map[string]interface{}{
"turn_id": turnID,
"model": model,
},
}
b, err := json.Marshal(rec)
if err != nil {
panic(err)
}
return string(b)
}
func TestResolveCodexModel_MatchesExactTurn(t *testing.T) {
codexHome := t.TempDir()
writeCodexRollout(t, codexHome, "abc", "20260725-180000", []string{
turnContextLine("turn-old", "gpt-5.5"),
turnContextLine("turn-7", "gpt-5.6-sol"),
})
t.Setenv("CODEX_HOME", codexHome)
got := resolveCodexModel("abc", "turn-7")
if got != "gpt-5.6-sol" {
t.Errorf("resolveCodexModel = %q, want gpt-5.6-sol", got)
}
}
func TestResolveCodexModel_DoesNotUseAnotherTurn(t *testing.T) {
codexHome := t.TempDir()
writeCodexRollout(t, codexHome, "abc", "20260725-180000", []string{
turnContextLine("turn-old", "gpt-5.5"),
})
t.Setenv("CODEX_HOME", codexHome)
got := resolveCodexModel("abc", "turn-7")
if got != "" {
t.Errorf("resolveCodexModel = %q, want empty (must not fall back to another turn)", got)
}
}
func TestResolveCodexModel_IgnoresBadIdentifiersAndMalformedRecords(t *testing.T) {
t.Run("malformed JSON skipped", func(t *testing.T) {
codexHome := t.TempDir()
writeCodexRollout(t, codexHome, "abc", "20260725-180000", []string{
"{not valid json",
turnContextLine("turn-7", "gpt-5.6-sol"),
})
t.Setenv("CODEX_HOME", codexHome)
got := resolveCodexModel("abc", "turn-7")
if got != "gpt-5.6-sol" {
t.Errorf("resolveCodexModel = %q, want gpt-5.6-sol after skipping malformed line", got)
}
})
t.Run("path traversal thread rejected", func(t *testing.T) {
codexHome := t.TempDir()
writeCodexRollout(t, codexHome, "abc", "20260725-180000", []string{
turnContextLine("turn-7", "gpt-5.6-sol"),
})
t.Setenv("CODEX_HOME", codexHome)
got := resolveCodexModel("../abc", "turn-7")
if got != "" {
t.Errorf("resolveCodexModel = %q for ../thread, want empty", got)
}
})
t.Run("empty turn rejected", func(t *testing.T) {
codexHome := t.TempDir()
writeCodexRollout(t, codexHome, "abc", "20260725-180000", []string{
turnContextLine("turn-7", "gpt-5.6-sol"),
})
t.Setenv("CODEX_HOME", codexHome)
got := resolveCodexModel("abc", "")
if got != "" {
t.Errorf("resolveCodexModel = %q for empty turn, want empty", got)
}
})
}
func TestModelFromCodexRollout_UnreadablePathIsEmpty(t *testing.T) {
dir := t.TempDir()
// Passing a directory: os.Open succeeds but reading fails; must return empty.
got := modelFromCodexRollout(dir, "turn-7")
if got != "" {
t.Errorf("modelFromCodexRollout(dir) = %q, want empty", got)
}
}
func TestCodexNotify_ResolvesModelFromSession(t *testing.T) {
codexHome := t.TempDir()
writeCodexRollout(t, codexHome, "abc", "20260725-180000", []string{
turnContextLine("turn-old", "gpt-5.5"),
turnContextLine("turn-7", "gpt-5.6-sol"),
})
t.Setenv("CODEX_HOME", codexHome)
in := []byte(`{"type":"agent-turn-complete","thread-id":"abc","turn-id":"turn-7","last-assistant-message":"Built OK."}`)
m, err := CodexNotifyFromBytes(in)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if m.Model != "gpt-5.6-sol" {
t.Errorf("model = %q, want gpt-5.6-sol resolved from session rollout", m.Model)
}
}