-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathquery_integration_test.go
More file actions
221 lines (181 loc) · 6.46 KB
/
query_integration_test.go
File metadata and controls
221 lines (181 loc) · 6.46 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//go:build integration
package codexsdk
import (
"context"
"errors"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// skipIfCLINotInstalled skips the test if err indicates the Codex CLI binary
// is not found. Call this immediately after receiving the first non-nil error
// from Query or Client.Start.
func skipIfCLINotInstalled(t *testing.T, err error) {
t.Helper()
if _, ok := errors.AsType[*CLINotFoundError](err); ok {
t.Skip("Codex CLI not installed")
}
}
// TestQuery_WithPersonality tests that WithPersonality passes through to the CLI.
func TestQuery_WithPersonality(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
receivedResult := false
for msg, err := range Query(ctx, Text("Say hello"),
WithPermissionMode("bypassPermissions"),
WithPersonality("pragmatic"),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
if result, ok := msg.(*ResultMessage); ok {
receivedResult = true
require.False(t, result.IsError, "Query should not result in error")
}
}
require.True(t, receivedResult, "Should receive result message")
}
// TestQuery_WithServiceTier tests that WithServiceTier passes through to the CLI.
func TestQuery_WithServiceTier(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
receivedResult := false
for msg, err := range Query(ctx, Text("Say hello"),
WithPermissionMode("bypassPermissions"),
WithServiceTier("fast"),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
if result, ok := msg.(*ResultMessage); ok {
receivedResult = true
require.False(t, result.IsError, "Query should not result in error")
}
}
require.True(t, receivedResult, "Should receive result message")
}
// TestQuery_WithDeveloperInstructions tests that WithDeveloperInstructions
// passes through to the CLI and influences the response.
func TestQuery_WithDeveloperInstructions(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
receivedResult := false
for msg, err := range Query(ctx, Text("What is 2+2? Reply with just the number."),
WithPermissionMode("bypassPermissions"),
WithDeveloperInstructions("Always respond in plain text with no formatting."),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
if result, ok := msg.(*ResultMessage); ok {
receivedResult = true
require.False(t, result.IsError, "Query should not result in error")
}
}
require.True(t, receivedResult, "Should receive result message")
}
// TestQuery_WithEffortNone tests that WithEffort(EffortNone) is accepted.
func TestQuery_WithEffortNone(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
receivedResult := false
for msg, err := range Query(ctx, Text("What is 2+2? Reply with just the number."),
WithPermissionMode("bypassPermissions"),
WithEffort(EffortNone),
WithConfig(map[string]string{"web_search": "disabled"}),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
if result, ok := msg.(*ResultMessage); ok {
receivedResult = true
require.False(t, result.IsError, "Query should not result in error")
}
}
require.True(t, receivedResult, "Should receive result message")
}
// TestQuery_WithEffortMinimal_ErrorSurfaced verifies that an API error
// (e.g. incompatible tools with minimal effort) is surfaced as an
// AssistantMessage with an error type rather than being silently dropped.
func TestQuery_WithEffortMinimal_ErrorSurfaced(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
var sawError bool
// Intentionally do NOT disallow web_search — this should trigger an API error
// because web_search is incompatible with minimal effort.
for msg, err := range Query(ctx, Text("What is 2+2?"),
WithPermissionMode("bypassPermissions"),
WithEffort(EffortMinimal),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
if assistant, ok := msg.(*AssistantMessage); ok && assistant.Error != nil {
sawError = true
for _, block := range assistant.Content {
if tb, ok := block.(*TextBlock); ok {
t.Logf("Error surfaced: %s", tb.Text)
require.Contains(t, tb.Text, "web_search",
"Error should mention incompatible web_search tool")
}
}
}
}
require.True(t, sawError, "Should have received an AssistantMessage with error for incompatible tools")
}
// TestQuery_WithEffortMinimal tests that WithEffort(EffortMinimal) is accepted
// by the SDK and passed to the CLI. Note: "minimal" effort is only supported
// by certain models; the test verifies the SDK passes it through correctly
// and the CLI returns a result (which may be an error if the model doesn't
// support "minimal").
func TestQuery_WithEffortMinimal(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
receivedResult := false
for msg, err := range Query(ctx, Text("What is 2+2? Reply with just the number."),
WithPermissionMode("bypassPermissions"),
WithEffort(EffortMinimal),
WithConfig(map[string]string{"web_search": "disabled"}),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
if _, ok := msg.(*ResultMessage); ok {
receivedResult = true
}
}
require.True(t, receivedResult, "Should receive result message")
}
func TestQuery_WriteOnlyAllowsCodexFileCreate(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
tmpDir := t.TempDir()
targetFile := filepath.Join(tmpDir, "write-only-proof.txt")
for _, err := range Query(ctx,
Text("Create a new file named write-only-proof.txt containing exactly: write only proof"),
WithCwd(tmpDir),
WithPermissionMode("default"),
WithAllowedTools("Write"),
WithDisallowedTools("Bash"),
WithSystemPrompt(
"Use the built-in file editing tool to create the file. Do not use Bash. Do not answer without creating the file.",
),
) {
if err != nil {
skipIfCLINotInstalled(t, err)
t.Fatalf("Query failed: %v", err)
}
}
data, err := os.ReadFile(targetFile)
require.NoError(t, err, "codex should create the file when Write is the only allowed file-editing tool")
require.Equal(t, "write only proof", strings.TrimSpace(string(data)))
}