forked from sourcegit-scm/sourcegit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAgent.cs
More file actions
88 lines (76 loc) · 3.98 KB
/
Copy pathAgent.cs
File metadata and controls
88 lines (76 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OpenAI.Chat;
namespace SourceGit.AI
{
public class Agent
{
public Agent(Service service)
{
_service = service;
}
public async Task GenerateCommitMessageAsync(string repo, string changeList, Action<string> onUpdate, CancellationToken cancellation)
{
var chatClient = _service.GetChatClient();
if (chatClient == null)
throw new Exception("Failed to fetch available models from this service. Please check your configuration and try again.");
var options = new ChatCompletionOptions() { Tools = { ChatTools.GetDetailChangesInFile } };
#pragma warning disable SCME0001
options.Patch.Set("$.thinking"u8, Encoding.UTF8.GetBytes("""{"type": "disabled"}"""));
options.Patch.Set("$.enable_thinking"u8, false);
#pragma warning restore SCME0001
var userMessageBuilder = new StringBuilder();
userMessageBuilder
.AppendLine("Generate a commit message (follow the rule of conventional commit message) for given git repository.")
.AppendLine("- Read all given changed files before generating. Only binary files (such as images, audios ...) can be skipped.")
.AppendLine("- Output the conventional commit message (with detail changes in list) directly. Do not explain your output nor introduce your answer.")
.AppendLine(_service.AdditionalPrompt)
.Append("Repository path: ").AppendLine(repo.Quoted())
.AppendLine("Changed files ('A' means added, 'M' means modified, 'D' means deleted, 'T' means type changed, 'R' means renamed, 'C' means copied): ")
.Append(changeList);
var messages = new List<ChatMessage>() { new UserChatMessage(userMessageBuilder.ToString()) };
do
{
ChatCompletion completion = await chatClient.CompleteChatAsync(messages, options, cancellation);
var inProgress = false;
switch (completion.FinishReason)
{
case ChatFinishReason.Stop:
onUpdate?.Invoke(string.Empty);
onUpdate?.Invoke("# Assistant");
if (completion.Content.Count > 0)
onUpdate?.Invoke(completion.Content[0].Text);
else
onUpdate?.Invoke("[No content was generated.]");
onUpdate?.Invoke(string.Empty);
onUpdate?.Invoke("# Token Usage");
onUpdate?.Invoke($"Total: {completion.Usage.TotalTokenCount}. Input: {completion.Usage.InputTokenCount}. Output: {completion.Usage.OutputTokenCount}");
break;
case ChatFinishReason.Length:
throw new Exception("The response was cut off because it reached the maximum length. Consider increasing the max tokens limit.");
case ChatFinishReason.ToolCalls:
{
messages.Add(new AssistantChatMessage(completion));
foreach (var call in completion.ToolCalls)
{
var result = await ChatTools.ProcessAsync(call, onUpdate);
messages.Add(result);
}
inProgress = true;
break;
}
case ChatFinishReason.ContentFilter:
throw new Exception("Omitted content due to a content filter flag");
default:
break;
}
if (!inProgress)
break;
} while (true);
}
private readonly Service _service;
}
}