返回 DeepSeek-Reasonix
inputimages_test.go
根目录 / internal / control / inputimages_test.go
1 package control
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 "reasonix/internal/config"
10 )
11
12 func writeVisionTestConfig(t *testing.T, root string) {
13 t.Helper()
14 cfg := config.Default()
15 cfg.DefaultModel = "custom/vision-pro"
16 cfg.Providers = []config.ProviderEntry{{
17 Name: "custom",
18 Kind: "openai",
19 BaseURL: "https://example.invalid/v1",
20 Models: []string{"text-only", "vision-pro"},
21 VisionModels: []string{"vision-pro"},
22 }}
23 if err := cfg.SaveTo(filepath.Join(root, "reasonix.toml")); err != nil {
24 t.Fatalf("save config: %v", err)
25 }
26 }
27
28 func TestControllerInputImagesResolvesAttachment(t *testing.T) {
29 dir := t.TempDir()
30 t.Chdir(dir)
31 writeVisionTestConfig(t, dir)
32 ref, err := SaveImageDataURL("data:image/png;base64," + tinyPNG)
33 if err != nil {
34 t.Fatalf("SaveImageDataURL: %v", err)
35 }
36 urls := (&Controller{modelRef: "custom/vision-pro"}).inputImages("look at @" + ref)
37 if len(urls) != 1 {
38 t.Fatalf("inputImages = %v, want one resolved data URL", urls)
39 }
40 if !strings.HasPrefix(urls[0], "data:image/png;base64,") {
41 t.Errorf("resolved url = %q, want a png data URL", urls[0])
42 }
43 }
44
45 func TestControllerInputImagesIgnoresNonAttachmentRefs(t *testing.T) {
46 t.Chdir(t.TempDir())
47 if urls := New(Options{}).inputImages("plain text with @missing.png"); len(urls) != 0 {
48 t.Errorf("inputImages = %v, want none for a non-existent / non-attachment ref", urls)
49 }
50 }
51
52 func TestControllerInputImagesResolvesWorkspaceImage(t *testing.T) {
53 workspace := t.TempDir()
54 writeVisionTestConfig(t, workspace)
55 path := filepath.Join(workspace, "docs", "diagram.png")
56 if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
57 t.Fatal(err)
58 }
59 if err := os.WriteFile(path, mustBase64(t, tinyPNG), 0o644); err != nil {
60 t.Fatal(err)
61 }
62
63 urls := (&Controller{workspaceRoot: workspace, modelRef: "custom/vision-pro"}).inputImages("look at @docs/diagram.png")
64 if len(urls) != 1 {
65 t.Fatalf("inputImages = %v, want one resolved data URL", urls)
66 }
67 if !strings.HasPrefix(urls[0], "data:image/png;base64,") {
68 t.Errorf("resolved url = %q, want a png data URL", urls[0])
69 }
70 }
71
72 func TestControllerInputImagesResolvesAbsoluteWorkspaceImage(t *testing.T) {
73 workspace := t.TempDir()
74 writeVisionTestConfig(t, workspace)
75 path := filepath.Join(workspace, "diagram.png")
76 if err := os.WriteFile(path, mustBase64(t, tinyPNG), 0o644); err != nil {
77 t.Fatal(err)
78 }
79
80 urls := (&Controller{workspaceRoot: workspace, modelRef: "custom/vision-pro"}).inputImages("look at @" + path)
81 if len(urls) != 1 {
82 t.Fatalf("inputImages = %v, want one resolved data URL", urls)
83 }
84 if !strings.HasPrefix(urls[0], "data:image/png;base64,") {
85 t.Errorf("resolved url = %q, want a png data URL", urls[0])
86 }
87 }
88
89 func TestControllerInputImagesRequiresWorkspaceForFileImageRefs(t *testing.T) {
90 dir := t.TempDir()
91 path := filepath.Join(dir, "diagram.png")
92 if err := os.WriteFile(path, mustBase64(t, tinyPNG), 0o644); err != nil {
93 t.Fatal(err)
94 }
95
96 urls := New(Options{}).inputImages("look at @" + path)
97 if len(urls) != 0 {
98 t.Fatalf("inputImages without a workspace = %v, want no file image refs", urls)
99 }
100 }
101
102 func TestControllerInputImagesSkipsModelImagesWhenSelectedModelIsTextOnly(t *testing.T) {
103 workspace := t.TempDir()
104 cfg := config.Default()
105 cfg.DefaultModel = "custom/text-only"
106 cfg.Providers = []config.ProviderEntry{{
107 Name: "custom",
108 Kind: "openai",
109 BaseURL: "https://example.invalid/v1",
110 Models: []string{"text-only", "vision-pro"},
111 VisionModels: []string{"vision-pro"},
112 }}
113 if err := cfg.SaveTo(filepath.Join(workspace, "reasonix.toml")); err != nil {
114 t.Fatalf("save workspace config: %v", err)
115 }
116 path := filepath.Join(workspace, "diagram.png")
117 if err := os.WriteFile(path, mustBase64(t, tinyPNG), 0o644); err != nil {
118 t.Fatal(err)
119 }
120
121 c := &Controller{workspaceRoot: workspace, modelRef: "custom/text-only"}
122 if urls := c.inputImages("look at @diagram.png"); len(urls) != 0 {
123 t.Fatalf("text-only model should suppress image payloads, got %v", urls)
124 }
125
126 c.modelRef = "custom/vision-pro"
127 if urls := c.inputImages("look at @diagram.png"); len(urls) != 1 {
128 t.Fatalf("vision model should keep image payloads, got %v", urls)
129 }
130 }
131
132 func TestControllerImageInputEnabledDoesNotFallbackFromUnknownRef(t *testing.T) {
133 workspace := t.TempDir()
134 writeVisionTestConfig(t, workspace)
135
136 c := &Controller{workspaceRoot: workspace, modelRef: "deleted/model"}
137 if c.imageInputEnabled() {
138 t.Fatal("unknown ref should not inherit image input from the default fallback model")
139 }
140 }
141
141 lines GO