feat: support disabling system prompt

This commit is contained in:
Carl-Robert Linnupuu 2025-02-03 02:00:37 +00:00
parent 38d935ac73
commit fab8d416ee
12 changed files with 80 additions and 30 deletions

View file

@ -26,6 +26,7 @@ public class CustomServiceFormTabbedPane extends JBTabbedPane {
bodyTable = new JBTable(
new DefaultTableModel(toArray(body),
new Object[]{"Key", "Value"}));
bodyTable.setVisibleRowCount(6);
setTabComponentInsets(JBUI.insetsTop(8));
addTab("Headers", createTablePanel(headersTable));

View file

@ -16,6 +16,7 @@ import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.components.ActionLink;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.JBUI.CurrentTheme.Link;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.actions.toolwindow.ClearChatWindowAction;
import ee.carlrobert.codegpt.actions.toolwindow.CreateNewConversationAction;
@ -23,6 +24,7 @@ import ee.carlrobert.codegpt.actions.toolwindow.OpenInEditorAction;
import ee.carlrobert.codegpt.conversations.ConversationService;
import ee.carlrobert.codegpt.conversations.ConversationsState;
import ee.carlrobert.codegpt.settings.GeneralSettings;
import ee.carlrobert.codegpt.settings.prompts.PersonaPromptDetailsState;
import ee.carlrobert.codegpt.settings.prompts.PromptsConfigurable;
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings;
import ee.carlrobert.codegpt.settings.service.ProviderChangeNotifier;
@ -164,16 +166,30 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
this.project = project;
}
private void showPromptsSettingsDialog() {
ShowSettingsUtil.getInstance()
.showSettingsDialog(project, PromptsConfigurable.class);
}
@Override
@NotNull
public JComponent createCustomComponent(
@NotNull Presentation presentation,
@NotNull String place) {
var link = new ActionLink(getSelectedPersonaName(), (e) -> {
ShowSettingsUtil.getInstance()
.showSettingsDialog(project, PromptsConfigurable.class);
var selectedPersona = getSelectedPersona();
var personaName = selectedPersona.getName();
if (personaName == null) {
personaName = "No persona selected";
}
var link = new ActionLink(personaName, (e) -> {
showPromptsSettingsDialog();
});
link.setExternalLinkIcon();
if (selectedPersona.getDisabled()) {
link.setToolTipText("Persona is disabled");
link.setForeground(JBUI.CurrentTheme.Label.disabledForeground());
}
link.setFont(JBUI.Fonts.smallFont());
link.setBorder(JBUI.Borders.empty(0, 4));
return link;
@ -183,19 +199,32 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
public void updateCustomComponent(
@NotNull JComponent component,
@NotNull Presentation presentation) {
((ActionLink) component).setText(getSelectedPersonaName());
if (component instanceof ActionLink actionLink) {
var selectedPersona = getSelectedPersona();
var personaName = selectedPersona.getName();
if (personaName == null) {
personaName = "No persona selected";
}
if (selectedPersona.getDisabled()) {
actionLink.setText(personaName + " (disabled)");
actionLink.setForeground(Link.Foreground.DISABLED);
} else {
actionLink.setText(personaName);
actionLink.setForeground(Link.Foreground.ENABLED);
}
}
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
}
private String getSelectedPersonaName() {
private PersonaPromptDetailsState getSelectedPersona() {
return ApplicationManager.getApplication().getService(PromptsSettings.class)
.getState()
.getPersonas()
.getSelectedPersona()
.getName();
.getSelectedPersona();
}
}
}
}

View file

@ -4,7 +4,6 @@ import com.intellij.openapi.components.service
import ee.carlrobert.codegpt.completions.BaseRequestFactory
import ee.carlrobert.codegpt.completions.ChatCompletionParameters
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
import ee.carlrobert.codegpt.settings.persona.PersonaSettings
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings
import ee.carlrobert.llm.client.anthropic.completion.*
@ -17,7 +16,11 @@ class ClaudeRequestFactory : BaseRequestFactory() {
model = service<AnthropicSettings>().state.model
maxTokens = service<ConfigurationSettings>().state.maxTokens
isStream = true
system = PromptsSettings.getSelectedPersonaSystemPrompt()
val selectedPersona = service<PromptsSettings>().state.personas.selectedPersona
if (!selectedPersona.disabled) {
system = PromptsSettings.getSelectedPersonaSystemPrompt()
}
messages = params.conversation.messages
.filter { it.response != null && it.response.isNotEmpty() }

View file

@ -96,13 +96,16 @@ class GoogleRequestFactory : BaseRequestFactory() {
when (params.conversationType) {
ConversationType.DEFAULT -> {
messages.add(
GoogleCompletionContent(
"user",
listOf(PromptsSettings.getSelectedPersonaSystemPrompt())
val selectedPersona = service<PromptsSettings>().state.personas.selectedPersona
if (!selectedPersona.disabled) {
messages.add(
GoogleCompletionContent(
"user",
listOf(PromptsSettings.getSelectedPersonaSystemPrompt())
)
)
)
messages.add(GoogleCompletionContent("model", listOf("Understood.")))
messages.add(GoogleCompletionContent("model", listOf("Understood.")))
}
}
ConversationType.FIX_COMPILE_ERRORS -> {

View file

@ -16,10 +16,14 @@ class LlamaRequestFactory : BaseRequestFactory() {
override fun createChatRequest(params: ChatCompletionParameters): LlamaCompletionRequest {
val promptTemplate = getPromptTemplate()
val systemPrompt =
if (params.conversationType == ConversationType.FIX_COMPILE_ERRORS)
if (params.conversationType == ConversationType.FIX_COMPILE_ERRORS) {
service<PromptsSettings>().state.coreActions.fixCompileErrors.instructions
else
PromptsSettings.getSelectedPersonaSystemPrompt()
} else {
service<PromptsSettings>().state.personas.selectedPersona.let {
if (it.disabled) null else it.instructions
}
}
val prompt = promptTemplate.buildPrompt(
systemPrompt,
getPromptWithFilesContext(params),

View file

@ -11,7 +11,6 @@ import ee.carlrobert.codegpt.settings.prompts.CoreActionsState
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings
import ee.carlrobert.codegpt.util.file.FileUtil.getImageMediaType
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel.*
import ee.carlrobert.llm.client.openai.completion.request.*
import java.io.IOException
@ -133,7 +132,7 @@ class OpenAIRequestFactory : CompletionRequestFactory {
.sum() + getState().maxTokens
val modelMaxTokens: Int
try {
modelMaxTokens = OpenAIChatCompletionModel.findByCode(model).maxTokens
modelMaxTokens = findByCode(model).maxTokens
if (totalUsage <= modelMaxTokens) {
return messages
@ -158,14 +157,12 @@ class OpenAIRequestFactory : CompletionRequestFactory {
val messages = mutableListOf<OpenAIChatCompletionMessage>()
val role = if (isReasoningModel(model)) "user" else "system"
if (callParameters.conversationType == ConversationType.DEFAULT) {
val selectedPersona = service<PromptsSettings>().state.personas.selectedPersona
if (callParameters.conversationType == ConversationType.DEFAULT && !selectedPersona.disabled) {
val sessionPersonaDetails = callParameters.personaDetails
if (sessionPersonaDetails == null) {
messages.add(
OpenAIChatCompletionStandardMessage(
role,
PromptsSettings.getSelectedPersonaSystemPrompt()
)
OpenAIChatCompletionStandardMessage(role, selectedPersona.instructions)
)
} else {
messages.add(

View file

@ -196,6 +196,7 @@ class ChatActionPromptDetailsState : PromptDetailsState() {
class PersonaPromptDetailsState : PromptDetailsState() {
var id by property(1L)
var disabled by property(false)
}
@JvmRecord

View file

@ -208,7 +208,8 @@ class PromptsForm {
.all { (details, prompt) ->
details.id == prompt.id &&
details.name == prompt.name &&
details.instructions == prompt.instructions
details.instructions == prompt.instructions &&
details.disabled == prompt.disabled
}
}

View file

@ -39,6 +39,7 @@ object PromptsFormUtil {
state.id = this.id
state.name = this.name
state.instructions = this.instructions
state.disabled = this.disabled
return state
}

View file

@ -61,11 +61,13 @@ data class PersonaPromptDetails(
override var name: String?,
override var instructions: String?,
val id: Long,
var selected: AtomicBooleanProperty = AtomicBooleanProperty(false)
var selected: AtomicBooleanProperty = AtomicBooleanProperty(false),
var disabled: Boolean = false
) : FormPromptDetails() {
constructor(state: PersonaPromptDetailsState) : this(
name = state.name,
instructions = state.instructions,
id = state.id
id = state.id,
disabled = state.disabled
)
}

View file

@ -5,10 +5,12 @@ import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.editor.event.DocumentListener
import com.intellij.openapi.observable.util.not
import com.intellij.ui.CardLayoutPanel
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.components.JBTextField
import com.intellij.ui.dsl.builder.Align
import com.intellij.ui.dsl.builder.TopGap
import com.intellij.ui.dsl.builder.panel
import com.intellij.ui.dsl.builder.selected
import com.intellij.ui.layout.ComponentPredicate
import com.intellij.util.ui.components.BorderLayoutPanel
import ee.carlrobert.codegpt.settings.prompts.PersonasState.Companion.DEFAULT_PERSONA_PROMPT
@ -95,6 +97,12 @@ class PersonasDetailsPanel(onSelected: (PersonaPromptDetails) -> Unit) : PromptD
.align(Align.FILL)
.onChanged { details.name = it.text }
}
row {
checkBox("Disable persona")
.selected(details.disabled)
.comment("If checked, the selected persona will not be used when making chat queries. This is particularly useful when the model does not support system prompt.")
.onChanged { details.disabled = it.isSelected }
}
row {
button("Set as Default") {
onSelected(details)

View file

@ -142,7 +142,7 @@ configurationConfigurable.section.codeCompletion.multiLineCompletions.descriptio
configurationConfigurable.section.codeCompletion.postProcess.title=Enable tree-sitter post-processing
configurationConfigurable.section.codeCompletion.postProcess.description=If checked, the completion will be post-processed using the tree-sitter parser.
configurationConfigurable.section.codeCompletion.gitDiff.title=Enable git diff context
configurationConfigurable.section.codeCompletion.collectDependencyStructure.title=Collect the dependencies of the analyzed file.
configurationConfigurable.section.codeCompletion.collectDependencyStructure.title=Enable dependency analyzer
configurationConfigurable.section.codeCompletion.collectDependencyStructure.description=Enabling the setting allows the plugin to collect the dependency structure, which increases the accuracy of the proposed data, but consumes more tokens per request. Currently, it is implemented only for the Kotlin language.
configurationConfigurable.section.codeCompletion.gitDiff.description=If checked, the user's most recent unstaged git diff will be included when requesting completion.
settingsConfigurable.service.llama.topK.label=Top K: