mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-05 08:55:28 +08:00
627 lines
22 KiB
Go
627 lines
22 KiB
Go
package openai
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"errors"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/go-chi/chi/v5"
|
||
|
||
"ds2api/internal/auth"
|
||
dsclient "ds2api/internal/deepseek/client"
|
||
"ds2api/internal/promptcompat"
|
||
)
|
||
|
||
func historySplitTestMessages() []any {
|
||
toolCalls := []any{
|
||
map[string]any{
|
||
"name": "search",
|
||
"arguments": map[string]any{"query": "docs"},
|
||
},
|
||
}
|
||
return []any{
|
||
map[string]any{"role": "system", "content": "system instructions"},
|
||
map[string]any{"role": "user", "content": "first user turn"},
|
||
map[string]any{
|
||
"role": "assistant",
|
||
"content": "",
|
||
"reasoning_content": "hidden reasoning",
|
||
"tool_calls": toolCalls,
|
||
},
|
||
map[string]any{
|
||
"role": "tool",
|
||
"name": "search",
|
||
"tool_call_id": "call-1",
|
||
"content": "tool result",
|
||
},
|
||
map[string]any{"role": "user", "content": "latest user turn"},
|
||
}
|
||
}
|
||
|
||
type streamStatusManagedAuthStub struct{}
|
||
|
||
func (streamStatusManagedAuthStub) Determine(_ *http.Request) (*auth.RequestAuth, error) {
|
||
return &auth.RequestAuth{
|
||
UseConfigToken: true,
|
||
DeepSeekToken: "managed-token",
|
||
CallerID: "caller:test",
|
||
AccountID: "acct:test",
|
||
TriedAccounts: map[string]bool{},
|
||
}, nil
|
||
}
|
||
|
||
func (streamStatusManagedAuthStub) DetermineCaller(_ *http.Request) (*auth.RequestAuth, error) {
|
||
return (&streamStatusManagedAuthStub{}).Determine(nil)
|
||
}
|
||
|
||
func (streamStatusManagedAuthStub) Release(_ *auth.RequestAuth) {}
|
||
|
||
func TestBuildOpenAICurrentInputContextTranscriptUsesInjectedFileWrapper(t *testing.T) {
|
||
_, historyMessages := splitOpenAIHistoryMessages(historySplitTestMessages(), 1)
|
||
transcript := buildOpenAICurrentInputContextTranscript(historyMessages)
|
||
|
||
if !strings.HasPrefix(transcript, "[file content end]\n\n") {
|
||
t.Fatalf("expected injected file wrapper prefix, got %q", transcript)
|
||
}
|
||
if !strings.Contains(transcript, "<|begin▁of▁sentence|>") {
|
||
t.Fatalf("expected serialized conversation markers, got %q", transcript)
|
||
}
|
||
if !strings.Contains(transcript, "first user turn") || !strings.Contains(transcript, "tool result") {
|
||
t.Fatalf("expected historical turns preserved, got %q", transcript)
|
||
}
|
||
if !strings.Contains(transcript, "[reasoning_content]") || !strings.Contains(transcript, "hidden reasoning") {
|
||
t.Fatalf("expected reasoning block preserved, got %q", transcript)
|
||
}
|
||
if !strings.Contains(transcript, "<|DSML|tool_calls>") {
|
||
t.Fatalf("expected tool calls preserved, got %q", transcript)
|
||
}
|
||
if !strings.HasSuffix(transcript, "\n[file name]: IGNORE\n[file content begin]\n") {
|
||
t.Fatalf("expected injected file wrapper suffix, got %q", transcript)
|
||
}
|
||
}
|
||
|
||
func TestSplitOpenAIHistoryMessagesUsesLatestUserTurn(t *testing.T) {
|
||
messages := []any{
|
||
map[string]any{"role": "system", "content": "system instructions"},
|
||
map[string]any{"role": "user", "content": "first user turn"},
|
||
map[string]any{"role": "assistant", "content": "first assistant turn"},
|
||
map[string]any{"role": "user", "content": "middle user turn"},
|
||
map[string]any{"role": "assistant", "content": "middle assistant turn"},
|
||
map[string]any{"role": "user", "content": "latest user turn"},
|
||
}
|
||
|
||
promptMessages, historyMessages := splitOpenAIHistoryMessages(messages, 1)
|
||
if len(promptMessages) == 0 || len(historyMessages) == 0 {
|
||
t.Fatalf("expected both prompt and history messages, got prompt=%d history=%d", len(promptMessages), len(historyMessages))
|
||
}
|
||
|
||
promptText, _ := promptcompat.BuildOpenAIPrompt(promptMessages, nil, "", defaultToolChoicePolicy(), true)
|
||
if !strings.Contains(promptText, "latest user turn") {
|
||
t.Fatalf("expected latest user turn in prompt, got %s", promptText)
|
||
}
|
||
if strings.Contains(promptText, "middle user turn") {
|
||
t.Fatalf("expected middle user turn to be moved into history, got %s", promptText)
|
||
}
|
||
|
||
historyText := buildOpenAICurrentInputContextTranscript(historyMessages)
|
||
if !strings.Contains(historyText, "middle user turn") {
|
||
t.Fatalf("expected middle user turn in split history, got %s", historyText)
|
||
}
|
||
if strings.Contains(historyText, "latest user turn") {
|
||
t.Fatalf("expected latest user turn to remain live, got %s", historyText)
|
||
}
|
||
}
|
||
|
||
func TestApplyCurrentInputFileSkipsShortInputWhenThresholdNotReached(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
currentInputMin: 10,
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": []any{
|
||
map[string]any{"role": "user", "content": "hello"},
|
||
},
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply current input file failed: %v", err)
|
||
}
|
||
if len(ds.uploadCalls) != 0 {
|
||
t.Fatalf("expected no upload on first turn, got %d", len(ds.uploadCalls))
|
||
}
|
||
if out.FinalPrompt != stdReq.FinalPrompt {
|
||
t.Fatalf("expected prompt unchanged on first turn")
|
||
}
|
||
}
|
||
|
||
func TestApplyThinkingInjectionAppendsLatestUserPrompt(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
thinkingInjection: boolPtr(true),
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": []any{
|
||
map[string]any{"role": "user", "content": "hello"},
|
||
},
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply thinking injection failed: %v", err)
|
||
}
|
||
if len(ds.uploadCalls) != 0 {
|
||
t.Fatalf("expected no upload for first short turn, got %d", len(ds.uploadCalls))
|
||
}
|
||
if !strings.Contains(out.FinalPrompt, "hello\n\n"+promptcompat.ThinkingInjectionMarker) {
|
||
t.Fatalf("expected thinking injection after latest user message, got %s", out.FinalPrompt)
|
||
}
|
||
}
|
||
|
||
func TestApplyThinkingInjectionUsesCustomPrompt(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
thinkingInjection: boolPtr(true),
|
||
thinkingPrompt: "custom thinking format",
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": []any{
|
||
map[string]any{"role": "user", "content": "hello"},
|
||
},
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply thinking injection failed: %v", err)
|
||
}
|
||
if !strings.Contains(out.FinalPrompt, "hello\n\ncustom thinking format") {
|
||
t.Fatalf("expected custom thinking injection after latest user message, got %s", out.FinalPrompt)
|
||
}
|
||
}
|
||
|
||
func TestApplyCurrentInputFileDisabledPassThrough(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: false,
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply current input file failed: %v", err)
|
||
}
|
||
if len(ds.uploadCalls) != 0 {
|
||
t.Fatalf("expected no uploads when both split modes are disabled, got %d", len(ds.uploadCalls))
|
||
}
|
||
if out.CurrentInputFileApplied || out.HistoryText != "" {
|
||
t.Fatalf("expected direct pass-through, got current_input=%v history=%q", out.CurrentInputFileApplied, out.HistoryText)
|
||
}
|
||
if !strings.Contains(out.FinalPrompt, "first user turn") || !strings.Contains(out.FinalPrompt, "latest user turn") {
|
||
t.Fatalf("expected original prompt context to stay inline, got %s", out.FinalPrompt)
|
||
}
|
||
}
|
||
|
||
func TestApplyCurrentInputFileUploadsFirstTurnWithInjectedWrapper(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
currentInputMin: 10,
|
||
thinkingInjection: boolPtr(true),
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": []any{
|
||
map[string]any{"role": "user", "content": "first turn content that is long enough"},
|
||
},
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply current input file failed: %v", err)
|
||
}
|
||
if len(ds.uploadCalls) != 1 {
|
||
t.Fatalf("expected 1 current input upload, got %d", len(ds.uploadCalls))
|
||
}
|
||
upload := ds.uploadCalls[0]
|
||
if upload.Filename != "IGNORE.txt" {
|
||
t.Fatalf("unexpected upload filename: %q", upload.Filename)
|
||
}
|
||
uploadedText := string(upload.Data)
|
||
if !strings.HasPrefix(uploadedText, "[file content end]\n\n") {
|
||
t.Fatalf("expected injected file wrapper prefix, got %q", uploadedText)
|
||
}
|
||
if !strings.Contains(uploadedText, "<|begin▁of▁sentence|><|User|>first turn content that is long enough") {
|
||
t.Fatalf("expected serialized current user turn markers, got %q", uploadedText)
|
||
}
|
||
if !strings.Contains(uploadedText, promptcompat.ThinkingInjectionMarker) {
|
||
t.Fatalf("expected thinking injection in current input file, got %q", uploadedText)
|
||
}
|
||
if !strings.HasSuffix(uploadedText, "\n[file name]: IGNORE\n[file content begin]\n") {
|
||
t.Fatalf("expected injected file wrapper suffix, got %q", uploadedText)
|
||
}
|
||
if strings.Contains(out.FinalPrompt, "first turn content that is long enough") {
|
||
t.Fatalf("expected current input text to be replaced in live prompt, got %s", out.FinalPrompt)
|
||
}
|
||
if strings.Contains(out.FinalPrompt, "CURRENT_USER_INPUT.txt") || strings.Contains(out.FinalPrompt, "IGNORE.txt") || strings.Contains(out.FinalPrompt, "Read that file") {
|
||
t.Fatalf("expected live prompt not to instruct file reads, got %s", out.FinalPrompt)
|
||
}
|
||
if !strings.Contains(out.FinalPrompt, "Answer the latest user request directly.") {
|
||
t.Fatalf("expected neutral continuation instruction in live prompt, got %s", out.FinalPrompt)
|
||
}
|
||
if len(out.RefFileIDs) != 1 || out.RefFileIDs[0] != "file-inline-1" {
|
||
t.Fatalf("expected current input file id in ref_file_ids, got %#v", out.RefFileIDs)
|
||
}
|
||
}
|
||
|
||
func TestApplyCurrentInputFileUploadsFullContextFile(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
currentInputMin: 0,
|
||
thinkingInjection: boolPtr(true),
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply current input file failed: %v", err)
|
||
}
|
||
if !out.CurrentInputFileApplied {
|
||
t.Fatalf("expected current input file to apply")
|
||
}
|
||
if len(ds.uploadCalls) != 1 {
|
||
t.Fatalf("expected one current input upload, got %d", len(ds.uploadCalls))
|
||
}
|
||
upload := ds.uploadCalls[0]
|
||
if upload.Filename != "IGNORE.txt" {
|
||
t.Fatalf("expected IGNORE.txt upload, got %q", upload.Filename)
|
||
}
|
||
uploadedText := string(upload.Data)
|
||
for _, want := range []string{"system instructions", "first user turn", "hidden reasoning", "tool result", "latest user turn", promptcompat.ThinkingInjectionMarker} {
|
||
if !strings.Contains(uploadedText, want) {
|
||
t.Fatalf("expected full context file to contain %q, got %q", want, uploadedText)
|
||
}
|
||
}
|
||
if strings.Contains(out.FinalPrompt, "first user turn") || strings.Contains(out.FinalPrompt, "latest user turn") || strings.Contains(out.FinalPrompt, "CURRENT_USER_INPUT.txt") || strings.Contains(out.FinalPrompt, "IGNORE.txt") || strings.Contains(out.FinalPrompt, "Read that file") {
|
||
t.Fatalf("expected live prompt to use only a neutral continuation instruction, got %s", out.FinalPrompt)
|
||
}
|
||
if !strings.Contains(out.FinalPrompt, "Answer the latest user request directly.") {
|
||
t.Fatalf("expected neutral continuation instruction in live prompt, got %s", out.FinalPrompt)
|
||
}
|
||
}
|
||
|
||
func TestApplyCurrentInputFileLeavesHistoryTextEmpty(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
},
|
||
DS: ds,
|
||
}
|
||
req := map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
}
|
||
stdReq, err := promptcompat.NormalizeOpenAIChatRequest(h.Store, req, "")
|
||
if err != nil {
|
||
t.Fatalf("normalize failed: %v", err)
|
||
}
|
||
|
||
out, err := h.applyCurrentInputFile(context.Background(), &auth.RequestAuth{DeepSeekToken: "token"}, stdReq)
|
||
if err != nil {
|
||
t.Fatalf("apply current input file failed: %v", err)
|
||
}
|
||
if len(ds.uploadCalls) != 1 {
|
||
t.Fatalf("expected 1 upload call, got %d", len(ds.uploadCalls))
|
||
}
|
||
if out.HistoryText != "" {
|
||
t.Fatalf("expected current input file flow to leave history text empty, got %q", out.HistoryText)
|
||
}
|
||
}
|
||
|
||
func TestChatCompletionsCurrentInputFileUploadsContextAndKeepsNeutralPrompt(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
},
|
||
Auth: streamStatusAuthStub{},
|
||
DS: ds,
|
||
}
|
||
reqBody, _ := json.Marshal(map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
"stream": false,
|
||
})
|
||
req := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(string(reqBody)))
|
||
req.Header.Set("Authorization", "Bearer direct-token")
|
||
req.Header.Set("Content-Type", "application/json")
|
||
rec := httptest.NewRecorder()
|
||
|
||
h.ChatCompletions(rec, req)
|
||
|
||
if rec.Code != http.StatusOK {
|
||
t.Fatalf("expected 200, got %d body=%s", rec.Code, rec.Body.String())
|
||
}
|
||
if len(ds.uploadCalls) != 1 {
|
||
t.Fatalf("expected 1 upload call, got %d", len(ds.uploadCalls))
|
||
}
|
||
upload := ds.uploadCalls[0]
|
||
if upload.Filename != "IGNORE.txt" {
|
||
t.Fatalf("unexpected upload filename: %q", upload.Filename)
|
||
}
|
||
if upload.Purpose != "assistants" {
|
||
t.Fatalf("unexpected purpose: %q", upload.Purpose)
|
||
}
|
||
historyText := string(upload.Data)
|
||
if !strings.Contains(historyText, "[file content end]") || !strings.Contains(historyText, "[file name]: IGNORE") {
|
||
t.Fatalf("expected injected IGNORE wrapper, got %s", historyText)
|
||
}
|
||
if !strings.Contains(historyText, "latest user turn") {
|
||
t.Fatalf("expected full context to include latest turn, got %s", historyText)
|
||
}
|
||
if ds.completionReq == nil {
|
||
t.Fatal("expected completion payload to be captured")
|
||
}
|
||
promptText, _ := ds.completionReq["prompt"].(string)
|
||
if !strings.Contains(promptText, "Answer the latest user request directly.") {
|
||
t.Fatalf("expected neutral completion prompt, got %s", promptText)
|
||
}
|
||
if strings.Contains(promptText, "first user turn") || strings.Contains(promptText, "latest user turn") {
|
||
t.Fatalf("expected prompt to hide original turns, got %s", promptText)
|
||
}
|
||
refIDs, _ := ds.completionReq["ref_file_ids"].([]any)
|
||
if len(refIDs) == 0 || refIDs[0] != "file-inline-1" {
|
||
t.Fatalf("expected uploaded current input file to be first ref_file_id, got %#v", ds.completionReq["ref_file_ids"])
|
||
}
|
||
}
|
||
|
||
func TestResponsesCurrentInputFileUploadsContextAndKeepsNeutralPrompt(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
},
|
||
Auth: streamStatusAuthStub{},
|
||
DS: ds,
|
||
}
|
||
r := chi.NewRouter()
|
||
registerOpenAITestRoutes(r, h)
|
||
reqBody, _ := json.Marshal(map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
"stream": false,
|
||
})
|
||
req := httptest.NewRequest(http.MethodPost, "/v1/responses", strings.NewReader(string(reqBody)))
|
||
req.Header.Set("Authorization", "Bearer direct-token")
|
||
req.Header.Set("Content-Type", "application/json")
|
||
rec := httptest.NewRecorder()
|
||
|
||
r.ServeHTTP(rec, req)
|
||
|
||
if rec.Code != http.StatusOK {
|
||
t.Fatalf("expected 200, got %d body=%s", rec.Code, rec.Body.String())
|
||
}
|
||
if len(ds.uploadCalls) != 1 {
|
||
t.Fatalf("expected 1 upload call, got %d", len(ds.uploadCalls))
|
||
}
|
||
if ds.completionReq == nil {
|
||
t.Fatal("expected completion payload to be captured")
|
||
}
|
||
promptText, _ := ds.completionReq["prompt"].(string)
|
||
if !strings.Contains(promptText, "Answer the latest user request directly.") {
|
||
t.Fatalf("expected neutral completion prompt, got %s", promptText)
|
||
}
|
||
if strings.Contains(promptText, "first user turn") || strings.Contains(promptText, "latest user turn") {
|
||
t.Fatalf("expected prompt to hide original turns, got %s", promptText)
|
||
}
|
||
}
|
||
|
||
func TestChatCompletionsCurrentInputFileMapsManagedAuthFailureTo401(t *testing.T) {
|
||
ds := &inlineUploadDSStub{
|
||
uploadErr: &dsclient.RequestFailure{Op: "upload file", Kind: dsclient.FailureManagedUnauthorized, Message: "expired token"},
|
||
}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
},
|
||
Auth: streamStatusManagedAuthStub{},
|
||
DS: ds,
|
||
}
|
||
reqBody, _ := json.Marshal(map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
"stream": false,
|
||
})
|
||
req := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(string(reqBody)))
|
||
req.Header.Set("Authorization", "Bearer managed-key")
|
||
req.Header.Set("Content-Type", "application/json")
|
||
rec := httptest.NewRecorder()
|
||
|
||
h.ChatCompletions(rec, req)
|
||
|
||
if rec.Code != http.StatusUnauthorized {
|
||
t.Fatalf("expected 401, got %d body=%s", rec.Code, rec.Body.String())
|
||
}
|
||
if !strings.Contains(rec.Body.String(), "Please re-login the account in admin") {
|
||
t.Fatalf("expected managed auth error message, got %s", rec.Body.String())
|
||
}
|
||
}
|
||
|
||
func TestResponsesCurrentInputFileMapsDirectAuthFailureTo401(t *testing.T) {
|
||
ds := &inlineUploadDSStub{
|
||
uploadErr: &dsclient.RequestFailure{Op: "upload file", Kind: dsclient.FailureDirectUnauthorized, Message: "invalid token"},
|
||
}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
},
|
||
Auth: streamStatusAuthStub{},
|
||
DS: ds,
|
||
}
|
||
r := chi.NewRouter()
|
||
registerOpenAITestRoutes(r, h)
|
||
reqBody, _ := json.Marshal(map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
"stream": false,
|
||
})
|
||
req := httptest.NewRequest(http.MethodPost, "/v1/responses", strings.NewReader(string(reqBody)))
|
||
req.Header.Set("Authorization", "Bearer direct-token")
|
||
req.Header.Set("Content-Type", "application/json")
|
||
rec := httptest.NewRecorder()
|
||
|
||
r.ServeHTTP(rec, req)
|
||
|
||
if rec.Code != http.StatusUnauthorized {
|
||
t.Fatalf("expected 401, got %d body=%s", rec.Code, rec.Body.String())
|
||
}
|
||
if !strings.Contains(rec.Body.String(), "Invalid token") {
|
||
t.Fatalf("expected direct auth error message, got %s", rec.Body.String())
|
||
}
|
||
}
|
||
|
||
func TestChatCompletionsCurrentInputFileUploadFailureReturnsInternalServerError(t *testing.T) {
|
||
ds := &inlineUploadDSStub{uploadErr: errors.New("boom")}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
currentInputEnabled: true,
|
||
},
|
||
Auth: streamStatusAuthStub{},
|
||
DS: ds,
|
||
}
|
||
reqBody, _ := json.Marshal(map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
"stream": false,
|
||
})
|
||
req := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(string(reqBody)))
|
||
req.Header.Set("Authorization", "Bearer direct-token")
|
||
req.Header.Set("Content-Type", "application/json")
|
||
rec := httptest.NewRecorder()
|
||
|
||
h.ChatCompletions(rec, req)
|
||
|
||
if rec.Code != http.StatusInternalServerError {
|
||
t.Fatalf("expected 500, got %d body=%s", rec.Code, rec.Body.String())
|
||
}
|
||
}
|
||
|
||
func TestCurrentInputFileWorksAcrossAutoDeleteModes(t *testing.T) {
|
||
for _, mode := range []string{"none", "single", "all"} {
|
||
t.Run(mode, func(t *testing.T) {
|
||
ds := &inlineUploadDSStub{}
|
||
h := &openAITestSurface{
|
||
Store: mockOpenAIConfig{
|
||
wideInput: true,
|
||
autoDeleteMode: mode,
|
||
currentInputEnabled: true,
|
||
},
|
||
Auth: streamStatusAuthStub{},
|
||
DS: ds,
|
||
}
|
||
reqBody, _ := json.Marshal(map[string]any{
|
||
"model": "deepseek-v4-flash",
|
||
"messages": historySplitTestMessages(),
|
||
"stream": false,
|
||
})
|
||
req := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(string(reqBody)))
|
||
req.Header.Set("Authorization", "Bearer direct-token")
|
||
req.Header.Set("Content-Type", "application/json")
|
||
rec := httptest.NewRecorder()
|
||
|
||
h.ChatCompletions(rec, req)
|
||
|
||
if rec.Code != http.StatusOK {
|
||
t.Fatalf("expected 200, got %d body=%s", rec.Code, rec.Body.String())
|
||
}
|
||
if len(ds.uploadCalls) != 1 {
|
||
t.Fatalf("expected current input upload for mode=%s, got %d", mode, len(ds.uploadCalls))
|
||
}
|
||
if ds.completionReq == nil {
|
||
t.Fatalf("expected completion payload for mode=%s", mode)
|
||
}
|
||
promptText, _ := ds.completionReq["prompt"].(string)
|
||
if !strings.Contains(promptText, "Answer the latest user request directly.") || strings.Contains(promptText, "first user turn") || strings.Contains(promptText, "latest user turn") {
|
||
t.Fatalf("unexpected prompt for mode=%s: %s", mode, promptText)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func defaultToolChoicePolicy() promptcompat.ToolChoicePolicy {
|
||
return promptcompat.DefaultToolChoicePolicy()
|
||
}
|
||
|
||
func boolPtr(v bool) *bool {
|
||
return &v
|
||
}
|