// Package deepseek provides a minimal client for the DeepSeek API, // which is compatible with the OpenAI chat completions format. package deepseek import ( "bytes" "encoding/json" "fmt" "net/http" "time" ) const ( apiURL = "https://api.deepseek.com/chat/completions" model = "deepseek-coder" systemPrompt = `You are an expert code reviewer. When given a pull request diff, you: - Identify bugs, logic errors, and edge cases - Flag security vulnerabilities (injections, auth issues, data exposure, etc.) - Note performance concerns - Point out style or maintainability issues - Highlight anything that looks unfinished or unclear Be specific: reference file names and line numbers where relevant. Be concise: skip praise for obvious or trivial things. Format your response in Markdown with clear sections. If the diff is clean, say so briefly.` ) // Client is a DeepSeek API client. type Client struct { APIKey string http *http.Client } // New creates a new DeepSeek client. func New(apiKey string) *Client { return &Client{ APIKey: apiKey, http: &http.Client{Timeout: 120 * time.Second}, } } type chatMessage struct { Role string `json:"role"` Content string `json:"content"` } type chatRequest struct { Model string `json:"model"` Messages []chatMessage `json:"messages"` } type chatResponse struct { Choices []struct { Message chatMessage `json:"message"` } `json:"choices"` Error *struct { Message string `json:"message"` } `json:"error,omitempty"` } // Review sends a PR diff to deepseek-coder and returns the review text. func (c *Client) Review(title, diff string) (string, error) { userContent := fmt.Sprintf("Please review this pull request.\n\n**Title:** %s\n\n```diff\n%s\n```", title, diff) body, _ := json.Marshal(chatRequest{ Model: model, Messages: []chatMessage{ {Role: "system", Content: systemPrompt}, {Role: "user", Content: userContent}, }, }) req, err := http.NewRequest("POST", apiURL, bytes.NewReader(body)) if err != nil { return "", err } req.Header.Set("Authorization", "Bearer "+c.APIKey) req.Header.Set("Content-Type", "application/json") resp, err := c.http.Do(req) if err != nil { return "", err } defer resp.Body.Close() var r chatResponse if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { return "", fmt.Errorf("deepseek: decode response: %w", err) } if r.Error != nil { return "", fmt.Errorf("deepseek: %s", r.Error.Message) } if len(r.Choices) == 0 { return "", fmt.Errorf("deepseek: empty response") } return r.Choices[0].Message.Content, nil }