feat: include <think> tags in request

This commit is contained in:
Carl-Robert Linnupuu 2025-11-17 17:34:57 +00:00
parent eb6371f3d2
commit 1502cb5a4a
5 changed files with 27 additions and 17 deletions

View file

@ -29,7 +29,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
private static final Logger LOG = Logger.getInstance(
ToolWindowCompletionResponseEventListener.class);
private static final int UPDATE_INTERVAL_MS = 8;
private static final int UPDATE_INTERVAL_MS = 20;
private final Project project;
private final StringBuilder messageBuilder = new StringBuilder();
@ -73,7 +73,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
try {
messageBuilder.append(partialMessage);
var ongoingTokens = encodingManager.countTokens(messageBuilder.toString());
var ongoingTokens = encodingManager.countTokens(partialMessage);
messageBuffer.offer(partialMessage);
ApplicationManager.getApplication().invokeLater(() ->
totalTokensPanel.update(totalTokensPanel.getTokenDetails().getTotal() + ongoingTokens)
@ -163,6 +163,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
responsePanel.enableAllActions(true);
responseContainer.stopLoading();
responseContainer.hideCaret();
responseContainer.finishThinking();
CompletionProgressNotifier.update(project, false);
}
}

View file

@ -229,6 +229,15 @@ public class ChatMessageResponseBody extends JPanel {
}
}
public void finishThinking() {
ApplicationManager.getApplication().invokeLater(() -> {
var thoughtProcessPanel = getExistingThoughtProcessPanel();
if (thoughtProcessPanel != null && !thoughtProcessPanel.isFinished()) {
thoughtProcessPanel.setFinished();
}
});
}
public void clear() {
contentPanel.removeAll();
streamOutputParser.clear();

View file

@ -153,7 +153,7 @@ class OpenAIRequestFactory : BaseRequestFactory() {
val r = m.response?.trim().orEmpty()
if (r.isNotEmpty()) messages.add(OpenAIChatCompletionStandardMessage("assistant", r))
}
messages.add(OpenAIChatCompletionStandardMessage("user", "Generate SEARCH and REPLACE blocks."))
messages.add(OpenAIChatCompletionStandardMessage("user", "Implement."))
return messages
}
@ -317,15 +317,8 @@ class OpenAIRequestFactory : BaseRequestFactory() {
messages.add(OpenAIChatCompletionStandardMessage("user", prevMessage.prompt))
}
var response = prevMessage.response ?: ""
if (response.startsWith("<think>")) {
response = response
.replace("(?s)<think>.*?</think>".toRegex(), "")
.trim { it <= ' ' }
}
messages.add(
OpenAIChatCompletionStandardMessage("assistant", response)
OpenAIChatCompletionStandardMessage("assistant", prevMessage.response ?: "")
)
}

View file

@ -121,7 +121,7 @@ class CustomServicesSettings :
val modelSelection = service<ModelSelectionService>()
val featureSelection = modelSelection.getModelSelectionForFeature(featureType)
if (featureSelection.provider != ServiceType.CUSTOM_OPENAI)
if (featureSelection?.provider != ServiceType.CUSTOM_OPENAI)
throw IllegalStateException(
"Current selected ServiceType (${featureSelection}) is not of type 'CUSTOM_OPENAI'. " +
"This function should not be called in this context!"

View file

@ -236,17 +236,24 @@ class SseMessageParser : MessageParser {
segments: MutableList<Segment>,
state: ParserState.InThinking
): Boolean {
val thinkEndIdx = buffer.indexOf(THINK_END)
val currentBuffer = buffer.toString()
val combined = state.content + currentBuffer
val endIdxCombined = combined.indexOf(THINK_END)
return if (thinkEndIdx >= 0) {
val thinkingContent = state.content + buffer.substring(0, thinkEndIdx)
return if (endIdxCombined >= 0) {
val thinkingContent = combined.substring(0, endIdxCombined)
segments.add(Thinking(thinkingContent))
consumeFromBuffer(thinkEndIdx + THINK_END.length)
val consumedFromBuffer = (endIdxCombined + THINK_END.length - state.content.length)
.coerceAtLeast(0)
.coerceAtMost(currentBuffer.length)
consumeFromBuffer(consumedFromBuffer)
parserState = ParserState.Outside
true
} else {
if (buffer.isNotEmpty()) {
val newContent = state.content + buffer.toString()
val newContent = state.content + currentBuffer
segments.add(Thinking(newContent))
buffer.clear()
parserState = ParserState.InThinking(newContent)