返回 DeepSeek-Reasonix
realdeepseek_test.go
根目录 / internal / provider / responses / realdeepseek_test.go
1 //go:build live
2
3 package responses
4
5 import (
6 "context"
7 "encoding/json"
8 "os"
9 "strings"
10 "testing"
11 "time"
12
13 "reasonix/internal/provider"
14 )
15
16 // TestRealOpenCodeGoDeepSeekResponsesWebSearch exercises Reasonix's stateless
17 // Responses request, server-side web search, and replay-item capture against the
18 // OpenCode Go DeepSeek Flash route.
19 func TestRealOpenCodeGoDeepSeekResponsesWebSearch(t *testing.T) {
20 key := os.Getenv("OPENCODE_GO_API_KEY")
21 if key == "" {
22 t.Skip("OPENCODE_GO_API_KEY not set — skipping live probe")
23 }
24
25 p := New(Config{
26 Name: "opencode-go-deepseek-responses",
27 BaseURL: "https://opencode.ai/zen/go/v1",
28 Model: "deepseek-v4-flash",
29 APIKey: key,
30 KeyEnv: "OPENCODE_GO_API_KEY",
31 Effort: "high",
32 Mode: "stateless",
33 WebSearch: true,
34 MaxOutputTokens: 768,
35 })
36 messages := []provider.Message{{
37 Role: provider.RoleUser, Content: "Search the web for the OpenCode Go documentation and reply with one source URL.",
38 }}
39 first := collectLiveOpenCodeGoResponsesTurn(t, p, provider.Request{Messages: messages, MaxTokens: 768})
40 if strings.TrimSpace(first.text) == "" {
41 t.Fatal("OpenCode Go Responses web_search returned no assistant text")
42 }
43 if len(first.items) == 0 {
44 t.Fatal("OpenCode Go Responses returned no completed web_search_call replay item")
45 }
46 messages = append(messages,
47 provider.Message{Role: provider.RoleAssistant, Content: first.text, ResponsesItems: first.items},
48 provider.Message{Role: provider.RoleUser, Content: "Using the previous search result, reply with only the source domain."},
49 )
50 second := collectLiveOpenCodeGoResponsesTurn(t, p, provider.Request{Messages: messages, MaxTokens: 256})
51 if strings.TrimSpace(second.text) == "" {
52 t.Fatal("OpenCode Go Responses stateless replay returned no follow-up text")
53 }
54 t.Logf("opencode-go-deepseek-responses: first_text=%d replay_items=%d second_text=%d", len(first.text), len(first.items), len(second.text))
55 }
56
57 type liveOpenCodeGoResponsesTurn struct {
58 text string
59 items []json.RawMessage
60 }
61
62 func collectLiveOpenCodeGoResponsesTurn(t *testing.T, p provider.Provider, req provider.Request) liveOpenCodeGoResponsesTurn {
63 t.Helper()
64 ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
65 defer cancel()
66 stream, err := p.Stream(ctx, req)
67 if err != nil {
68 t.Fatalf("Stream: %v", err)
69 }
70 var out liveOpenCodeGoResponsesTurn
71 var text strings.Builder
72 for chunk := range stream {
73 switch chunk.Type {
74 case provider.ChunkText:
75 text.WriteString(chunk.Text)
76 case provider.ChunkResponsesItem:
77 out.items = append(out.items, append(json.RawMessage(nil), chunk.ResponsesItem...))
78 case provider.ChunkError:
79 t.Fatalf("stream error: %v", chunk.Err)
80 }
81 }
82 out.text = text.String()
83 return out
84 }
85
86 // TestRealDeepSeekResponsesWebSearch exercises the official stateless
87 // Responses endpoint with its provider-executed web_search tool. It is
88 // credential-gated and build-tagged so ordinary CI remains deterministic.
89 func TestRealDeepSeekResponsesWebSearch(t *testing.T) {
90 key := os.Getenv("DEEPSEEK_API_KEY")
91 if key == "" {
92 t.Skip("DEEPSEEK_API_KEY not set — skipping live probe")
93 }
94
95 p := New(Config{
96 Name: "deepseek-responses",
97 BaseURL: "https://api.deepseek.com",
98 Model: "deepseek-v4-flash",
99 APIKey: key,
100 Effort: "disabled",
101 WebSearch: true,
102 MaxOutputTokens: 256,
103 KeyEnv: "DEEPSEEK_API_KEY",
104 })
105 chunks := collect(t, p, provider.Request{Messages: []provider.Message{{
106 Role: provider.RoleUser,
107 Content: "Search the web for the latest DeepSeek API documentation update and reply with one source URL.",
108 }}, MaxTokens: 256})
109 var text strings.Builder
110 for _, chunk := range chunks {
111 if chunk.Type == provider.ChunkText {
112 text.WriteString(chunk.Text)
113 }
114 }
115 if strings.TrimSpace(text.String()) == "" {
116 t.Fatalf("web_search returned no assistant text")
117 }
118 t.Logf("web_search: text=%d chunks=%d", len(text.String()), len(chunks))
119 }
120
120 lines GO