@@ -76,20 +76,25 @@ func (p *OpenRouterProvider) GenerateCommitMessage(diff string, commitTypesJSON
7676 return "" , fmt .Errorf ("empty diff provided" )
7777 }
7878
79- // Enhance small diffs
80- diff = enhanceSmallDiff (diff )
79+ // Use smart diff summarization for better AI comprehension
80+ diffSummary , optimizedDiff := summarizeDiff (diff )
8181
82- // Truncate large diffs
83- originalDiffSize := len (diff )
84- diff = truncateDiff (diff )
85- if originalDiffSize != len (diff ) {
86- // Add warning to extra context if diff was truncated
82+ // Add summary info to context if diff was significantly reduced
83+ if diffSummary .SummarySize < diffSummary .OriginalSize {
8784 if extraContext != "" {
8885 extraContext += " "
8986 }
90- extraContext += fmt .Sprintf ("(Note: Diff was truncated from %d to %d characters due to size limits)" , originalDiffSize , len (diff ))
87+ extraContext += fmt .Sprintf ("(Diff summarized: %d files changed. %s)" ,
88+ len (diffSummary .FilesChanged ),
89+ diffSummary .Summary )
9190 }
9291
92+ // Use the optimized diff
93+ diff = optimizedDiff
94+
95+ // Still apply small diff enhancement if needed
96+ diff = enhanceSmallDiff (diff )
97+
9398 systemPrompt := `You are a commit message generator that follows these rules:
9499 1. Write in present tense
95100 2. Be concise and direct
@@ -182,6 +187,143 @@ Code diff:`
182187 return "" , fmt .Errorf ("no valid commit message found in response. Raw response: %s" , rawResult )
183188}
184189
190+ func (p * OpenRouterProvider ) GenerateDetailedCommit (diff string , commitTypesJSON string , extraContext string ) (* CommitResult , error ) {
191+ // Validate and enhance the diff
192+ if diff == "" {
193+ return nil , fmt .Errorf ("empty diff provided" )
194+ }
195+
196+ // Use smart diff summarization for better AI comprehension
197+ diffSummary , optimizedDiff := summarizeDiff (diff )
198+
199+ // Add summary info to context if diff was significantly reduced
200+ if diffSummary .SummarySize < diffSummary .OriginalSize {
201+ if extraContext != "" {
202+ extraContext += " "
203+ }
204+ extraContext += fmt .Sprintf ("(Diff summarized: %d files changed. %s)" ,
205+ len (diffSummary .FilesChanged ),
206+ diffSummary .Summary )
207+ }
208+
209+ // Use the optimized diff
210+ diff = optimizedDiff
211+ diff = enhanceSmallDiff (diff )
212+
213+ systemPrompt := `You are a commit message generator that generates both a concise title and a detailed body.
214+
215+ RULES FOR TITLE:
216+ 1. Write in present tense
217+ 2. Be concise and direct
218+ 3. Follow the format: <type>(<optional scope>): <commit message>
219+ 4. Keep the title under 72 characters
220+ 5. Focus on what changed, not how it changed
221+
222+ RULES FOR BODY:
223+ 1. Write in present tense
224+ 2. Provide 2-4 bullet points that explain the changes in depth
225+ 3. Each bullet point should be concise but informative
226+ 4. Focus on the WHY and WHAT of the changes
227+ 5. Reference specific files or functionality when relevant
228+
229+ VALID TYPES: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert
230+
231+ OUTPUT FORMAT:
232+ Title: <type>(<optional scope>): <commit message>
233+
234+ Body:
235+ • First detailed point about the changes
236+ • Second detailed point about the changes
237+ • Third detailed point about the changes (if applicable)
238+
239+ EXAMPLE OUTPUT:
240+ Title: feat(auth): add user authentication system
241+
242+ Body:
243+ • Add JWT token generation and validation middleware
244+ • Implement login/logout endpoints with secure password hashing
245+ • Create user model with role-based access control
246+ • Add authentication middleware to protect API routes`
247+
248+ userPrompt := fmt .Sprintf (`Generate a commit message with detailed body for the following code diff:
249+
250+ Follow the exact format specified. Include both a concise title and detailed bullet points in the body.
251+
252+ Choose a type from the type-to-description JSON below that best describes the git diff:
253+ %s
254+ ` , commitTypesJSON )
255+
256+ if extraContext != "" {
257+ userPrompt += fmt .Sprintf ("\n Additional context: %s\n " , extraContext )
258+ }
259+
260+ userPrompt += `Focus on being accurate and comprehensive.
261+ Code diff:`
262+ userPrompt += fmt .Sprintf ("\n ```diff\n %s\n ```" , diff )
263+
264+ requestPayload := OpenRouterRequest {
265+ Model : p .model ,
266+ Messages : []OpenRouterMessage {
267+ {Role : "system" , Content : systemPrompt },
268+ {Role : "user" , Content : userPrompt },
269+ },
270+ }
271+
272+ jsonPayload , err := json .Marshal (requestPayload )
273+ if err != nil {
274+ return nil , fmt .Errorf ("failed to marshal OpenRouter request payload: %w" , err )
275+ }
276+
277+ req , err := http .NewRequest ("POST" , openRouterAPIURL , bytes .NewBuffer (jsonPayload ))
278+ if err != nil {
279+ return nil , fmt .Errorf ("failed to create OpenRouter request: %w" , err )
280+ }
281+
282+ req .Header .Set ("Authorization" , "Bearer " + p .apiKey )
283+ req .Header .Set ("Content-Type" , "application/json" )
284+ req .Header .Set ("HTTP-Referer" , httpReferer )
285+ req .Header .Set ("X-Title" , xTitle )
286+ req .Header .Set ("Accept" , "application/json" )
287+
288+ resp , err := p .client .Do (req )
289+ if err != nil {
290+ return nil , fmt .Errorf ("failed to send request to OpenRouter: %w" , err )
291+ }
292+ defer resp .Body .Close ()
293+
294+ bodyBytes , err := io .ReadAll (resp .Body )
295+ if err != nil {
296+ return nil , fmt .Errorf ("failed to read OpenRouter response body: %w" , err )
297+ }
298+
299+ if resp .StatusCode != http .StatusOK {
300+ var errorResponse OpenRouterErrorResponse
301+ if err := json .Unmarshal (bodyBytes , & errorResponse ); err == nil && errorResponse .Error .Message != "" {
302+ return nil , fmt .Errorf ("openrouter API error (status %d): %s" , resp .StatusCode , errorResponse .Error .Message )
303+ }
304+ return nil , fmt .Errorf ("openrouter API returned status %d: %s" , resp .StatusCode , string (bodyBytes ))
305+ }
306+
307+ var successResponse OpenRouterResponse
308+ if err := json .Unmarshal (bodyBytes , & successResponse ); err != nil {
309+ return nil , fmt .Errorf ("failed to unmarshal OpenRouter success response: %w. Body: %s" , err , string (bodyBytes ))
310+ }
311+
312+ if len (successResponse .Choices ) == 0 || successResponse .Choices [0 ].Message .Content == "" {
313+ return nil , fmt .Errorf ("no content found in OpenRouter response or choices array is empty. Body: %s" , string (bodyBytes ))
314+ }
315+
316+ rawResult := successResponse .Choices [0 ].Message .Content
317+
318+ // Parse the detailed commit message to extract title and body
319+ result := parseDetailedCommitMessage (rawResult )
320+ if result .Message == "" {
321+ return nil , fmt .Errorf ("no valid commit message found in response. Raw response: %s" , rawResult )
322+ }
323+
324+ return result , nil
325+ }
326+
185327func (p * OpenRouterProvider ) GetModel () string {
186328 return p .model
187329}
0 commit comments