package completionruntime import ( "context" "io" "net/http" "strings" "testing" "ds2api/internal/auth" dsclient "ds2api/internal/deepseek/client" "ds2api/internal/promptcompat" ) type fakeDeepSeekCaller struct { responses []*http.Response payloads []map[string]any uploads []dsclient.UploadFileRequest } type currentInputRuntimeConfig struct{} func (currentInputRuntimeConfig) CurrentInputFileEnabled() bool { return true } func (currentInputRuntimeConfig) CurrentInputFileMinChars() int { return 0 } func (f *fakeDeepSeekCaller) CreateSession(context.Context, *auth.RequestAuth, int) (string, error) { return "session-1", nil } func (f *fakeDeepSeekCaller) GetPow(context.Context, *auth.RequestAuth, int) (string, error) { return "pow", nil } func (f *fakeDeepSeekCaller) UploadFile(_ context.Context, _ *auth.RequestAuth, req dsclient.UploadFileRequest, _ int) (*dsclient.UploadFileResult, error) { f.uploads = append(f.uploads, req) return &dsclient.UploadFileResult{ID: "file-runtime-1"}, nil } func (f *fakeDeepSeekCaller) CallCompletion(_ context.Context, _ *auth.RequestAuth, payload map[string]any, _ string, _ int) (*http.Response, error) { f.payloads = append(f.payloads, payload) if len(f.responses) == 0 { return sseHTTPResponse(http.StatusOK, `data: {"p":"response/content","v":"fallback"}`), nil } resp := f.responses[0] f.responses = f.responses[1:] return resp, nil } func TestExecuteNonStreamWithRetryBuildsCanonicalTurn(t *testing.T) { ds := &fakeDeepSeekCaller{responses: []*http.Response{sseHTTPResponse( http.StatusOK, `data: {"response_message_id":42,"p":"response/content","v":"{\"x\":1}"}`, )}} stdReq := promptcompat.StandardRequest{ Surface: "test", ResponseModel: "deepseek-v4-flash", PromptTokenText: "prompt", FinalPrompt: "final prompt", ToolNames: []string{"Write"}, ToolsRaw: []any{map[string]any{ "name": "Write", "input_schema": map[string]any{ "type": "object", "properties": map[string]any{ "content": map[string]any{"type": "string"}, }, }, }}, } result, outErr := ExecuteNonStreamWithRetry(context.Background(), ds, &auth.RequestAuth{}, stdReq, Options{}) if outErr != nil { t.Fatalf("unexpected output error: %#v", outErr) } if result.SessionID != "session-1" { t.Fatalf("session mismatch: %q", result.SessionID) } if got := result.Turn.ResponseMessageID; got != 42 { t.Fatalf("response message id mismatch: %d", got) } if len(result.Turn.ToolCalls) != 1 { t.Fatalf("expected one tool call, got %d", len(result.Turn.ToolCalls)) } if _, ok := result.Turn.ToolCalls[0].Input["content"].(string); !ok { t.Fatalf("expected schema-normalized string argument, got %#v", result.Turn.ToolCalls[0].Input["content"]) } if result.Turn.Usage.InputTokens == 0 || result.Turn.Usage.TotalTokens == 0 { t.Fatalf("expected usage to be populated, got %#v", result.Turn.Usage) } } func TestExecuteNonStreamWithRetryUsesParentMessageForEmptyRetry(t *testing.T) { ds := &fakeDeepSeekCaller{responses: []*http.Response{ sseHTTPResponse(http.StatusOK, `data: {"response_message_id":77,"p":"response/status","v":"FINISHED"}`), sseHTTPResponse(http.StatusOK, `data: {"response_message_id":78,"p":"response/content","v":"ok"}`), }} stdReq := promptcompat.StandardRequest{ Surface: "test", ResponseModel: "deepseek-v4-flash", PromptTokenText: "prompt", FinalPrompt: "final prompt", } result, outErr := ExecuteNonStreamWithRetry(context.Background(), ds, &auth.RequestAuth{}, stdReq, Options{RetryEnabled: true}) if outErr != nil { t.Fatalf("unexpected output error: %#v", outErr) } if result.Attempts != 1 { t.Fatalf("expected one retry, got %d", result.Attempts) } if len(ds.payloads) != 2 { t.Fatalf("expected two completion calls, got %d", len(ds.payloads)) } if got := ds.payloads[1]["parent_message_id"]; got != 77 { t.Fatalf("retry parent_message_id mismatch: %#v", got) } if result.Turn.Text != "ok" { t.Fatalf("retry text mismatch: %q", result.Turn.Text) } } func TestStartCompletionAppliesCurrentInputFileGlobally(t *testing.T) { ds := &fakeDeepSeekCaller{responses: []*http.Response{sseHTTPResponse(http.StatusOK, `data: {"p":"response/content","v":"ok"}`)}} stdReq := promptcompat.StandardRequest{ Surface: "test_adapter", RequestedModel: "deepseek-v4-flash", ResolvedModel: "deepseek-v4-flash", ResponseModel: "deepseek-v4-flash", PromptTokenText: "first user turn", FinalPrompt: "first user turn", Messages: []any{ map[string]any{"role": "user", "content": "first user turn"}, }, } start, outErr := StartCompletion(context.Background(), ds, &auth.RequestAuth{DeepSeekToken: "token"}, stdReq, Options{ CurrentInputFile: currentInputRuntimeConfig{}, }) if outErr != nil { t.Fatalf("unexpected output error: %#v", outErr) } if len(ds.uploads) != 1 { t.Fatalf("expected current input upload, got %d", len(ds.uploads)) } if got := ds.uploads[0].Filename; got != "DS2API_HISTORY.txt" { t.Fatalf("upload filename=%q want DS2API_HISTORY.txt", got) } if len(ds.payloads) != 1 { t.Fatalf("expected one completion payload, got %d", len(ds.payloads)) } refIDs, _ := ds.payloads[0]["ref_file_ids"].([]any) if len(refIDs) != 1 || refIDs[0] != "file-runtime-1" { t.Fatalf("expected uploaded file id in ref_file_ids, got %#v", ds.payloads[0]["ref_file_ids"]) } prompt, _ := ds.payloads[0]["prompt"].(string) if !strings.Contains(prompt, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") { t.Fatalf("expected continuation prompt, got %q", prompt) } if !start.Request.CurrentInputFileApplied || !strings.Contains(start.Request.PromptTokenText, "# DS2API_HISTORY.txt") { t.Fatalf("expected prepared request to carry current input file state, got %#v", start.Request) } } func sseHTTPResponse(status int, lines ...string) *http.Response { body := strings.Join(lines, "\n") if !strings.HasSuffix(body, "\n") { body += "\n" } return &http.Response{ StatusCode: status, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(body)), } }