refactor: chat request message building

This commit is contained in:
Carl-Robert Linnupuu 2024-11-18 10:38:19 +00:00
parent 1f74dd2311
commit 148946c5ee
28 changed files with 254 additions and 236 deletions

View file

@ -61,6 +61,10 @@ public final class EncodingManager {
}
public int countTokens(String text) {
if (text == null || text.isEmpty()) {
return 0;
}
try {
// #444: Cl100kParser.split() throws AssertionError "Input is not UTF-8: "
return encoding.countTokens(text.replaceAll("<|", "").replaceAll("|>", ""));

View file

@ -68,7 +68,6 @@ public class ProjectCompilationStatusListener implements CompilationStatusListen
message.setReferencedFilePaths(errorMapping.keySet().stream()
.map(ReferencedFile::getFilePath)
.toList());
message.setUserMessage(message.getPrompt());
message.setPrompt(CompletionRequestUtil.getPromptWithContext(
new ArrayList<>(errorMapping.keySet()),
prompt));

View file

@ -37,7 +37,6 @@ public class AskQuestionAction extends BaseEditorAction {
previousUserPrompt = dialog.getUserPrompt();
var message = new Message(
format("%s%n```%s%n%s%n```", previousUserPrompt, fileExtension, selectedText));
message.setUserMessage(previousUserPrompt);
SwingUtilities.invokeLater(() ->
project.getService(ChatToolWindowContentManager.class).sendMessage(message));
}

View file

@ -2,7 +2,6 @@ package ee.carlrobert.codegpt.actions.editor;
import static java.lang.String.format;
import com.intellij.icons.AllIcons.Actions;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
@ -11,7 +10,6 @@ import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.actions.IncludeFilesInContextAction;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowContentManager;
@ -53,15 +51,14 @@ public class EditorActionsUtil {
var action = new BaseEditorAction(label, label) {
@Override
protected void actionPerformed(Project project, Editor editor, String selectedText) {
var fileExtension = FileUtil.getFileExtension(editor.getVirtualFile().getName());
var message = new Message(prompt.replace(
"{{selectedCode}}",
format("%n```%s%n%s%n```", fileExtension, selectedText)));
message.setUserMessage(prompt.replace("{{selectedCode}}", ""));
var toolWindowContentManager =
project.getService(ChatToolWindowContentManager.class);
toolWindowContentManager.getToolWindow().show();
var fileExtension = FileUtil.getFileExtension(editor.getVirtualFile().getName());
var message = new Message(prompt.replace(
"{{selectedCode}}",
format("%n```%s%n%s%n```", fileExtension, selectedText)));
message.setReferencedFilePaths(
Stream.ofNullable(project.getUserData(CodeGPTKeys.SELECTED_FILES))
.flatMap(Collection::stream)

View file

@ -45,23 +45,28 @@ public class ChatCompletionEventListener implements CompletionEventListener<Stri
@Override
public void onComplete(StringBuilder messageBuilder) {
eventListener.handleCompleted(messageBuilder.toString(), callParameters);
handleCompleted(messageBuilder);
}
@Override
public void onCancelled(StringBuilder messageBuilder) {
eventListener.handleCompleted(messageBuilder.toString(), callParameters);
handleCompleted(messageBuilder);
}
@Override
public void onError(ErrorDetails error, Throwable ex) {
try {
callParameters.getConversation().addMessage(callParameters.getMessage());
eventListener.handleError(error, ex);
} finally {
sendError(error, ex);
}
}
private void handleCompleted(StringBuilder messageBuilder) {
eventListener.handleCompleted(messageBuilder.toString(), callParameters);
}
private void sendError(ErrorDetails error, Throwable ex) {
var telemetryMessage = TelemetryAction.COMPLETION_ERROR.createActionMessage();
if ("insufficient_quota".equals(error.getCode())) {

View file

@ -1,22 +1,21 @@
package ee.carlrobert.codegpt.conversations.message;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ee.carlrobert.codegpt.settings.persona.PersonaDetails;
import ee.carlrobert.codegpt.ui.DocumentationDetails;
import ee.carlrobert.llm.client.you.completion.YouSerpResult;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Message {
private final UUID id;
private String prompt;
private String response;
private String userMessage;
private List<YouSerpResult> serpResults;
private List<String> referencedFilePaths;
private @Nullable String imageFilePath;
private boolean webSearchIncluded;
@ -54,22 +53,6 @@ public class Message {
this.response = response;
}
public String getUserMessage() {
return userMessage;
}
public void setUserMessage(String userMessage) {
this.userMessage = userMessage;
}
public List<YouSerpResult> getSerpResults() {
return serpResults;
}
public void setSerpResults(List<YouSerpResult> serpResults) {
this.serpResults = serpResults;
}
public List<String> getReferencedFilePaths() {
return referencedFilePaths;
}

View file

@ -8,6 +8,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.CodeGPTKeys;
@ -21,7 +22,6 @@ import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.codegpt.conversations.ConversationService;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
import ee.carlrobert.codegpt.toolwindow.chat.actionprocessor.ActionProcessorFactory;
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatMessageResponseBody;
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatToolWindowScrollablePanel;
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
@ -37,9 +37,6 @@ import ee.carlrobert.codegpt.util.file.FileUtil;
import git4idea.GitCommit;
import java.awt.BorderLayout;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@ -89,7 +86,7 @@ public class ChatToolWindowTabPanel implements Disposable {
if (conversation.getMessages().isEmpty()) {
displayLandingView();
} else {
displayConversation(conversation);
displayConversation();
}
}
@ -118,8 +115,8 @@ public class ChatToolWindowTabPanel implements Disposable {
totalTokensPanel.updateConversationTokens(conversation);
}
public void addSelection(String fileName, SelectionModel selectionModel) {
userInputPanel.addSelection(fileName, selectionModel);
public void addSelection(VirtualFile editorFile, SelectionModel selectionModel) {
userInputPanel.addSelection(editorFile, selectionModel);
}
public void addCommitReferences(List<GitCommit> gitCommits) {
@ -153,42 +150,27 @@ public class ChatToolWindowTabPanel implements Disposable {
}
public void sendMessage(Message message, ConversationType conversationType) {
sendMessage(message, conversationType, null);
}
public void sendMessage(
Message message,
ConversationType conversationType,
@Nullable String highlightedText) {
ApplicationManager.getApplication().invokeLater(() -> {
List<ReferencedFile> referencedFiles = getReferencedFiles();
if (!referencedFiles.isEmpty()) {
message.setReferencedFilePaths(referencedFiles.stream()
.map(ReferencedFile::getFilePath)
.toList());
message.setUserMessage(message.getPrompt());
}
var callParameters = ChatCompletionParameters.builder(conversation, message)
.sessionId(chatSession.getId())
.conversationType(conversationType)
.imageDetailsFromPath(CodeGPTKeys.IMAGE_ATTACHMENT_FILE_PATH.get(project))
.referencedFiles(getReferencedFiles())
.build();
String attachedImagePath = CodeGPTKeys.IMAGE_ATTACHMENT_FILE_PATH.get(project);
if (attachedImagePath != null) {
message.setImageFilePath(attachedImagePath);
}
totalTokensPanel.updateConversationTokens(conversation);
totalTokensPanel.updateReferencedFilesTokens(referencedFiles);
if (attachedImagePath != null || !referencedFiles.isEmpty()) {
var referencedFiles = callParameters.getReferencedFiles();
if ((referencedFiles != null && !referencedFiles.isEmpty())
|| callParameters.getImageDetails() != null) {
project.getService(ChatToolWindowContentManager.class)
.tryFindChatToolWindowPanel()
.ifPresent(panel -> panel.clearNotifications(project));
}
var callParameters = getCallParameters(
message,
conversationType,
referencedFiles,
highlightedText,
attachedImagePath);
totalTokensPanel.updateConversationTokens(conversation);
if (callParameters.getReferencedFiles() != null) {
totalTokensPanel.updateReferencedFilesTokens(callParameters.getReferencedFiles());
}
var responsePanel = createResponsePanel(callParameters);
var messagePanel = toolWindowScrollablePanel.addMessage(message.getId());
messagePanel.add(new UserMessagePanel(project, message, this));
@ -198,30 +180,6 @@ public class ChatToolWindowTabPanel implements Disposable {
});
}
private ChatCompletionParameters getCallParameters(
Message message,
ConversationType conversationType,
List<ReferencedFile> referencedFiles,
@Nullable String highlightedText,
@Nullable String attachedImagePath) {
var builder = ChatCompletionParameters.builder(conversation, message)
.sessionId(chatSession.getId())
.conversationType(conversationType)
.highlightedText(highlightedText)
.referencedFiles(referencedFiles);
if (attachedImagePath != null && !attachedImagePath.isEmpty()) {
try {
builder
.imageData(Files.readAllBytes(Path.of(attachedImagePath)))
.imageMediaType(FileUtil.getImageMediaType(attachedImagePath));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return builder.build();
}
private boolean hasReferencedFilePaths(Message message) {
return message.getReferencedFilePaths() != null && !message.getReferencedFilePaths().isEmpty();
}
@ -243,7 +201,6 @@ public class ChatToolWindowTabPanel implements Disposable {
.addContent(
new ChatMessageResponseBody(
project,
callParameters.getHighlightedText(),
true,
false,
message.isWebSearchIncluded(),
@ -318,38 +275,21 @@ public class ChatToolWindowTabPanel implements Disposable {
}
private Unit handleSubmit(String text, List<? extends AppliedActionInlay> appliedInlayActions) {
var message = new Message(text);
var editor = EditorUtil.getSelectedEditor(project);
var messageBuilder = new MessageBuilder(project, text)
.withSelectedEditorContent()
.withInlays(appliedInlayActions);
var remainingText = new StringBuilder(text);
var promptBuilder = new StringBuilder();
for (var actionInlay : appliedInlayActions) {
var inlayOffset = actionInlay.getInlay().getOffset();
promptBuilder.append(remainingText, 0, Math.min(inlayOffset, remainingText.length()))
.append("\n");
ActionProcessorFactory.getProcessor(actionInlay)
.process(message, actionInlay, editor, promptBuilder);
remainingText.delete(0, inlayOffset);
}
promptBuilder.append(remainingText);
String selectedText = "";
String selectedTextMd = "";
if (editor != null) {
var selectionModel = editor.getSelectionModel();
selectedText = selectionModel.getSelectedText();
if (selectedText != null && !selectedText.isEmpty()) {
var fileExtension = FileUtil.getFileExtension(editor.getVirtualFile().getName());
selectedTextMd = format("\n```%s\n%s\n```\n", fileExtension, selectedText);
selectionModel.removeSelection();
}
List<ReferencedFile> referencedFiles = getReferencedFiles();
if (!referencedFiles.isEmpty()) {
messageBuilder.withReferencedFiles(referencedFiles);
}
message.setUserMessage(selectedTextMd + promptBuilder);
message.setPrompt(selectedTextMd + promptBuilder);
String attachedImagePath = CodeGPTKeys.IMAGE_ATTACHMENT_FILE_PATH.get(project);
if (attachedImagePath != null) {
messageBuilder.withImage(attachedImagePath);
}
sendMessage(message, ConversationType.DEFAULT, selectedText);
sendMessage(messageBuilder.build(), ConversationType.DEFAULT);
return Unit.INSTANCE;
}
@ -386,18 +326,17 @@ public class ChatToolWindowTabPanel implements Disposable {
var message = new Message(action.getPrompt().replace(
"{{selectedCode}}",
format("%n```%s%n%s%n```", fileExtension, editor.getSelectionModel().getSelectedText())));
message.setUserMessage(action.getUserMessage());
sendMessage(message, ConversationType.DEFAULT);
return Unit.INSTANCE;
});
}
private void displayConversation(@NotNull Conversation conversation) {
private void displayConversation() {
clearWindow();
conversation.getMessages().forEach(message -> {
var response = message.getResponse() == null ? "" : message.getResponse();
var messageResponseBody =
new ChatMessageResponseBody(project, this).withResponse(message.getResponse());
new ChatMessageResponseBody(project, this).withResponse(response);
messageResponseBody.hideCaret();

View file

@ -1,11 +1,9 @@
package ee.carlrobert.codegpt.toolwindow.chat.actionprocessor;
import com.intellij.openapi.editor.Editor;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.ui.textarea.AppliedActionInlay;
public interface ActionProcessor {
void process(Message message, AppliedActionInlay action, Editor editor,
StringBuilder promptBuilder);
void process(Message message, AppliedActionInlay action, StringBuilder promptBuilder);
}

View file

@ -1,14 +1,15 @@
package ee.carlrobert.codegpt.toolwindow.chat.actionprocessor;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.ui.textarea.AppliedActionInlay;
import ee.carlrobert.codegpt.ui.textarea.AppliedCodeActionInlay;
import ee.carlrobert.codegpt.ui.textarea.AppliedSuggestionActionInlay;
public class ActionProcessorFactory {
public static ActionProcessor getProcessor(AppliedActionInlay action) {
public static ActionProcessor getProcessor(Project project, AppliedActionInlay action) {
if (action instanceof AppliedSuggestionActionInlay) {
return new SuggestionActionProcessor();
return new SuggestionActionProcessor(project);
} else if (action instanceof AppliedCodeActionInlay) {
return new CodeActionProcessor();
}

View file

@ -1,6 +1,5 @@
package ee.carlrobert.codegpt.toolwindow.chat.actionprocessor;
import com.intellij.openapi.editor.Editor;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.ui.textarea.AppliedActionInlay;
import ee.carlrobert.codegpt.ui.textarea.AppliedCodeActionInlay;
@ -9,18 +8,16 @@ import ee.carlrobert.codegpt.util.file.FileUtil;
public class CodeActionProcessor implements ActionProcessor {
@Override
public void process(Message message, AppliedActionInlay action, Editor editor,
StringBuilder promptBuilder) {
public void process(Message message, AppliedActionInlay action, StringBuilder promptBuilder) {
if (!(action instanceof AppliedCodeActionInlay codeAction)) {
throw new IllegalArgumentException("Invalid action type");
}
processCodeAction(codeAction, editor, promptBuilder);
processCodeAction(codeAction, promptBuilder);
}
private void processCodeAction(AppliedCodeActionInlay action, Editor editor,
StringBuilder promptBuilder) {
private void processCodeAction(AppliedCodeActionInlay action, StringBuilder promptBuilder) {
promptBuilder
.append("\n```%s\n".formatted(FileUtil.getFileExtension(editor.getVirtualFile().getName())))
.append("\n```%s\n".formatted(FileUtil.getFileExtension(action.getEditorFile().getName())))
.append(action.getCode())
.append("\n```\n");
}

View file

@ -1,6 +1,5 @@
package ee.carlrobert.codegpt.toolwindow.chat.actionprocessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.conversations.message.Message;
@ -11,36 +10,38 @@ import ee.carlrobert.codegpt.ui.textarea.suggestion.item.DocumentationActionItem
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.GitCommitActionItem;
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.PersonaActionItem;
import ee.carlrobert.codegpt.ui.textarea.suggestion.item.WebSearchActionItem;
import org.jetbrains.annotations.Nullable;
public class SuggestionActionProcessor implements ActionProcessor {
private final Project project;
public SuggestionActionProcessor(Project project) {
this.project = project;
}
@Override
public void process(Message message, AppliedActionInlay action, Editor editor,
public void process(
Message message,
AppliedActionInlay action,
StringBuilder promptBuilder) {
if (!(action instanceof AppliedSuggestionActionInlay suggestionAction)) {
throw new IllegalArgumentException("Invalid action type");
}
processSuggestionAction(message, suggestionAction, editor, promptBuilder);
processSuggestionAction(message, suggestionAction, promptBuilder);
}
private void processSuggestionAction(
Message message,
AppliedSuggestionActionInlay action,
@Nullable Editor editor,
StringBuilder promptBuilder) {
message.setWebSearchIncluded(action.getSuggestion() instanceof WebSearchActionItem);
if (editor != null) {
processDocumentationAction(message, action, editor.getProject());
processPersonaAction(message, action, editor.getProject());
}
processDocumentationAction(message, action);
processPersonaAction(message, action);
processGitCommitAction(action, promptBuilder);
}
private void processDocumentationAction(
Message message,
AppliedSuggestionActionInlay action,
Project project) {
private void processDocumentationAction(Message message, AppliedSuggestionActionInlay action) {
var addedDocumentation = CodeGPTKeys.ADDED_DOCUMENTATION.get(project);
var appliedInlayExists = action.getSuggestion() instanceof DocumentationActionItem
|| action.getSuggestion() instanceof CreateDocumentationActionItem;
@ -51,10 +52,7 @@ public class SuggestionActionProcessor implements ActionProcessor {
}
}
private void processPersonaAction(
Message message,
AppliedSuggestionActionInlay action,
Project project) {
private void processPersonaAction(Message message, AppliedSuggestionActionInlay action) {
var addedPersona = CodeGPTKeys.ADDED_PERSONA.get(project);
var personaInlayExists = action.getSuggestion() instanceof PersonaActionItem;
if (addedPersona != null && personaInlayExists) {

View file

@ -38,7 +38,6 @@ import ee.carlrobert.codegpt.util.EditorUtil;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ResponseEditorPanel extends JPanel implements Disposable {
@ -49,7 +48,6 @@ public class ResponseEditorPanel extends JPanel implements Disposable {
String code,
String markdownLanguage,
boolean readOnly,
@Nullable String highlightedText,
Disposable disposableParent) {
super(new BorderLayout());
setBorder(JBUI.Borders.empty(8, 0));

View file

@ -43,7 +43,7 @@ import javax.swing.DefaultListModel;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
public class ChatMessageResponseBody extends JPanel {
@ -56,25 +56,22 @@ public class ChatMessageResponseBody extends JPanel {
private final DefaultListModel<WebSearchEventDetails> webpageListModel = new DefaultListModel<>();
private final WebpageList webpageList = new WebpageList(webpageListModel);
private final ResponseBodyProgressPanel progressPanel = new ResponseBodyProgressPanel();
private final @Nullable String highlightedText;
private ResponseEditorPanel currentlyProcessedEditorPanel;
private JEditorPane currentlyProcessedTextPane;
private JPanel webpageListPanel;
public ChatMessageResponseBody(Project project, Disposable parentDisposable) {
this(project, null, false, false, false, false, parentDisposable);
this(project, false, false, false, false, parentDisposable);
}
public ChatMessageResponseBody(
Project project,
@Nullable String highlightedText,
boolean withGhostText,
boolean readOnly,
boolean webSearchIncluded,
boolean withProgress,
Disposable parentDisposable) {
this.project = project;
this.highlightedText = highlightedText;
this.parentDisposable = parentDisposable;
this.streamParser = new StreamParser();
this.readOnly = readOnly;
@ -97,7 +94,7 @@ public class ChatMessageResponseBody extends JPanel {
}
}
public ChatMessageResponseBody withResponse(String response) {
public ChatMessageResponseBody withResponse(@NotNull String response) {
try {
for (var message : MarkdownUtil.splitCodeBlocks(response)) {
processResponse(message, message.startsWith("```"), false);
@ -265,9 +262,8 @@ public class ChatMessageResponseBody extends JPanel {
private void prepareProcessingCode(String code, String markdownLanguage) {
hideCaret();
currentlyProcessedTextPane = null;
currentlyProcessedEditorPanel = new ResponseEditorPanel(project, code, markdownLanguage,
readOnly, highlightedText,
parentDisposable);
currentlyProcessedEditorPanel =
new ResponseEditorPanel(project, code, markdownLanguage, readOnly, parentDisposable);
add(currentlyProcessedEditorPanel);
}

View file

@ -47,15 +47,10 @@ public class UserMessagePanel extends JPanel {
displayImage(message.getImageFilePath());
}
var referencedFilePaths = message.getReferencedFilePaths();
if (referencedFilePaths != null && !referencedFilePaths.isEmpty()) {
add(createResponseBody(
project,
message.getUserMessage(),
parentDisposable), BorderLayout.SOUTH);
} else {
add(createResponseBody(project, message.getPrompt(), parentDisposable), BorderLayout.SOUTH);
}
add(createResponseBody(
project,
message.getPrompt(),
parentDisposable), BorderLayout.SOUTH);
}
public @Nullable JPanel getAdditionalContextPanel(Project project, Message message) {
@ -99,7 +94,7 @@ public class UserMessagePanel extends JPanel {
Project project,
String prompt,
Disposable parentDisposable) {
return new ChatMessageResponseBody(project, null, false, true, false, false, parentDisposable)
return new ChatMessageResponseBody(project, false, true, false, false, parentDisposable)
.withResponse(prompt);
}

View file

@ -1,8 +1,5 @@
package ee.carlrobert.codegpt.toolwindow.chat.ui.textarea;
import ee.carlrobert.codegpt.EncodingManager;
import ee.carlrobert.codegpt.settings.persona.PersonaSettings;
public class TotalTokensDetails {
private final int systemPromptTokens;
@ -11,8 +8,8 @@ public class TotalTokensDetails {
private int highlightedTokens;
private int referencedFilesTokens;
public TotalTokensDetails(EncodingManager encodingManager) {
systemPromptTokens = encodingManager.countTokens(PersonaSettings.getSystemPrompt());
public TotalTokensDetails(int systemPromptTokens) {
this.systemPromptTokens = systemPromptTokens;
}
public int getSystemPromptTokens() {

View file

@ -19,7 +19,9 @@ import ee.carlrobert.codegpt.EncodingManager;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.GeneralSettings;
import ee.carlrobert.codegpt.settings.persona.PersonaSettings;
import ee.carlrobert.codegpt.settings.service.ServiceType;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
@ -105,6 +107,13 @@ public class TotalTokensPanel extends JPanel {
label.setText(getLabelHtml(total));
}
public void updateConversationTokens(Conversation conversation, Message message) {
totalTokensDetails.setConversationTokens(
encodingManager.countConversationTokens(conversation)
+ encodingManager.countMessageTokens("user", message.getPrompt()));
update();
}
public void updateConversationTokens(Conversation conversation) {
totalTokensDetails.setConversationTokens(encodingManager.countConversationTokens(conversation));
update();
@ -131,7 +140,8 @@ public class TotalTokensPanel extends JPanel {
Conversation conversation,
List<ReferencedFile> includedFiles,
@Nullable String highlightedText) {
var tokenDetails = new TotalTokensDetails(encodingManager);
var tokenDetails = new TotalTokensDetails(
encodingManager.countTokens(PersonaSettings.getSystemPrompt()));
tokenDetails.setConversationTokens(encodingManager.countConversationTokens(conversation));
if (includedFiles != null) {
tokenDetails.setReferencedFilesTokens(includedFiles.stream()