feat: add inception provider

This commit is contained in:
Carl-Robert Linnupuu 2025-10-06 01:38:09 +01:00
parent f8b36b294d
commit da50e55ba1
42 changed files with 674 additions and 183 deletions

View file

@ -12,7 +12,7 @@ jsoup = "1.21.2"
jtokkit = "1.1.0"
junit = "5.13.4"
kotlin = "2.2.10"
llm-client = "0.8.49"
llm-client = "0.8.52"
okio = "3.15.0"
tree-sitter = "0.24.5"
grpc = "1.73.0"

View file

@ -25,6 +25,7 @@ public final class Icons {
public static final Icon Meta = IconLoader.getIcon("/icons/meta.svg", Icons.class);
public static final Icon Mistral = IconLoader.getIcon("/icons/mistral.svg", Icons.class);
public static final Icon Moonshot = IconLoader.getIcon("/icons/moonshot.svg", Icons.class);
public static final Icon Inception = IconLoader.getIcon("/icons/inception.svg", Icons.class);
public static final Icon Send = IconLoader.getIcon("/icons/send.svg", Icons.class);
public static final Icon Sparkle = IconLoader.getIcon("/icons/sparkle.svg", Icons.class);
public static final Icon Ollama = IconLoader.getIcon("/icons/ollama.svg", Icons.class);

View file

@ -13,6 +13,7 @@ import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
import ee.carlrobert.llm.client.anthropic.ClaudeClient;
import ee.carlrobert.llm.client.codegpt.CodeGPTClient;
import ee.carlrobert.llm.client.google.GoogleClient;
import ee.carlrobert.llm.client.inception.InceptionClient;
import ee.carlrobert.llm.client.llama.LlamaClient;
import ee.carlrobert.llm.client.mistral.MistralClient;
import ee.carlrobert.llm.client.ollama.OllamaClient;
@ -78,6 +79,11 @@ public class CompletionClientProvider {
return new MistralClient(getCredential(CredentialKey.MistralApiKey.INSTANCE), getDefaultClientBuilder());
}
public static InceptionClient getInceptionClient() {
return new InceptionClient.Builder(getCredential(CredentialKey.InceptionApiKey.INSTANCE))
.build(getDefaultClientBuilder());
}
public static OkHttpClient.Builder getDefaultClientBuilder() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
CertificateManager certificateManager = CertificateManager.getInstance();

View file

@ -1,5 +1,7 @@
package ee.carlrobert.codegpt.completions;
import static ee.carlrobert.codegpt.settings.service.ServiceType.INCEPTION;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.diagnostic.Logger;
@ -14,7 +16,7 @@ import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionRequest;
import ee.carlrobert.llm.client.codegpt.request.InlineEditRequest;
import ee.carlrobert.llm.client.codegpt.request.chat.ChatCompletionRequest;
import ee.carlrobert.llm.client.google.completion.GoogleCompletionRequest;
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest;
import ee.carlrobert.llm.client.inception.request.InceptionApplyRequest;
import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionEventSourceListener;
import ee.carlrobert.llm.client.openai.completion.OpenAITextCompletionEventSourceListener;
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest;
@ -75,12 +77,17 @@ public final class CompletionRequestService {
public EventSource autoApplyAsync(
AutoApplyParameters params,
CompletionEventListener<String> eventListener) {
var serviceType =
var selectedService =
ModelSelectionService.getInstance().getServiceForFeature(FeatureType.AUTO_APPLY);
if (selectedService == INCEPTION) {
return null;
}
var request = CompletionRequestFactory
.getFactory(serviceType)
.getFactory(selectedService)
.createAutoApplyRequest(params);
return getChatCompletionAsync(request, eventListener, serviceType, FeatureType.AUTO_APPLY);
return getChatCompletionAsync(request, eventListener, selectedService, FeatureType.AUTO_APPLY);
}
public EventSource getCommitMessageAsync(
@ -129,6 +136,10 @@ public final class CompletionRequestService {
.getChatCompletionAsync(completionRequest, eventListener);
case MISTRAL -> CompletionClientProvider.getMistralClient()
.getChatCompletionAsync(completionRequest, eventListener);
case LLAMA_CPP -> CompletionClientProvider.getLlamaClient()
.getChatCompletionAsync(completionRequest, eventListener);
case INCEPTION -> CompletionClientProvider.getInceptionClient()
.getChatCompletionAsync(completionRequest, eventListener);
default -> throw new RuntimeException("Unknown service selected");
};
}
@ -150,11 +161,6 @@ public final class CompletionRequestService {
ModelSelectionService.getInstance().getModelForFeature(featureType, null),
eventListener);
}
if (request instanceof LlamaCompletionRequest completionRequest) {
return CompletionClientProvider.getLlamaClient().getChatCompletionAsync(
completionRequest,
eventListener);
}
throw new IllegalStateException("Unknown request type: " + request.getClass());
}
@ -169,6 +175,10 @@ public final class CompletionRequestService {
.getChatCompletion(completionRequest);
case MISTRAL -> CompletionClientProvider.getMistralClient()
.getChatCompletion(completionRequest);
case LLAMA_CPP -> CompletionClientProvider.getLlamaClient()
.getChatCompletion(completionRequest);
case INCEPTION -> CompletionClientProvider.getInceptionClient()
.getChatCompletion(completionRequest);
default -> throw new RuntimeException("Unknown service selected");
};
return tryExtractContent(response).orElseThrow();
@ -205,11 +215,6 @@ public final class CompletionRequestService {
.getContent().getParts().get(0)
.getText();
}
if (request instanceof LlamaCompletionRequest completionRequest) {
return CompletionClientProvider.getLlamaClient()
.getChatCompletion(completionRequest)
.getContent();
}
throw new IllegalStateException("Unknown request type: " + request.getClass());
}
@ -235,6 +240,8 @@ public final class CompletionRequestService {
case GOOGLE -> CredentialsStore.INSTANCE.isCredentialSet(CredentialKey.GoogleApiKey.INSTANCE);
case MISTRAL ->
CredentialsStore.INSTANCE.isCredentialSet(CredentialKey.MistralApiKey.INSTANCE);
case INCEPTION ->
CredentialsStore.INSTANCE.isCredentialSet(CredentialKey.InceptionApiKey.INSTANCE);
case PROXYAI, CUSTOM_OPENAI, LLAMA_CPP, OLLAMA -> true;
};
}

View file

@ -12,7 +12,8 @@ public enum ServiceType {
GOOGLE("GOOGLE", "service.google.title", "google.chat.completion"),
MISTRAL("MISTRAL", "service.mistral.title", "mistral.chat.completion"),
LLAMA_CPP("LLAMA_CPP", "service.llama.title", "llama.chat.completion"),
OLLAMA("OLLAMA", "service.ollama.title", "ollama.chat.completion");
OLLAMA("OLLAMA", "service.ollama.title", "ollama.chat.completion"),
INCEPTION("INCEPTION", "service.inception.title", "inception.chat.completion");
private final String code;
private final String label;

View file

@ -9,6 +9,7 @@ import static ee.carlrobert.codegpt.settings.service.ServiceType.MISTRAL;
import static ee.carlrobert.codegpt.settings.service.ServiceType.OLLAMA;
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
import static ee.carlrobert.codegpt.settings.service.ServiceType.PROXYAI;
import static ee.carlrobert.codegpt.settings.service.ServiceType.INCEPTION;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
@ -242,6 +243,13 @@ public class ModelComboBoxAction extends ComboBoxAction {
actionGroup.add(mistralGroup);
}
if (availableProviders.contains(INCEPTION)) {
var inceptionGroup = DefaultActionGroup.createPopupGroup(() -> "Inception");
inceptionGroup.getTemplatePresentation().setIcon(Icons.Inception);
inceptionGroup.add(createInceptionModelAction(presentation));
actionGroup.add(inceptionGroup);
}
if (availableProviders.contains(LLAMA_CPP) || availableProviders.contains(OLLAMA)) {
actionGroup.addSeparator("Offline");
@ -344,6 +352,11 @@ public class ModelComboBoxAction extends ComboBoxAction {
templatePresentation.setText(getMistralPresentationText());
templatePresentation.setIcon(Icons.Mistral);
break;
case INCEPTION:
templatePresentation.setIcon(Icons.Inception);
var inceptionModelName = ModelRegistry.getInstance().getModelDisplayName(INCEPTION, modelCode);
templatePresentation.setText(inceptionModelName);
break;
default:
break;
}
@ -525,6 +538,18 @@ public class ModelComboBoxAction extends ComboBoxAction {
.setModel(featureType, modelCode, MISTRAL));
}
private AnAction createInceptionModelAction(Presentation comboBoxPresentation) {
var modelCode = ModelRegistry.MERCURY_CODER;
var modelName = ModelRegistry.getInstance().getModelDisplayName(INCEPTION, modelCode);
return createModelAction(
INCEPTION,
modelName,
Icons.Inception,
comboBoxPresentation,
() -> ApplicationManager.getApplication().getService(ModelSettings.class)
.setModel(featureType, modelCode, INCEPTION));
}
private String getMistralPresentationText() {
var chatModel = ApplicationManager.getApplication().getService(ModelSettings.class).getState()
.getModelSelection(featureType);

View file

@ -14,6 +14,7 @@ import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings
import ee.carlrobert.codegpt.settings.service.mistral.MistralSettings
import ee.carlrobert.codegpt.settings.service.inception.InceptionSettings
abstract class CodeCompletionFeatureToggleActions(
private val enableFeatureAction: Boolean
@ -50,6 +51,10 @@ abstract class CodeCompletionFeatureToggleActions(
MistralSettings.getCurrentState().isCodeCompletionsEnabled = enableFeatureAction
}
INCEPTION -> {
service<InceptionSettings>().state.codeCompletionsEnabled = enableFeatureAction
}
ANTHROPIC,
GOOGLE -> {
}
@ -68,7 +73,8 @@ abstract class CodeCompletionFeatureToggleActions(
CUSTOM_OPENAI,
LLAMA_CPP,
OLLAMA,
MISTRAL -> true
MISTRAL,
INCEPTION -> true
ANTHROPIC,
GOOGLE -> false

View file

@ -10,11 +10,15 @@ import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import ee.carlrobert.codegpt.CodeGPTKeys
import ee.carlrobert.codegpt.codecompletions.edit.NextEditCoordinator
import ee.carlrobert.codegpt.codecompletions.edit.GrpcClientService
import ee.carlrobert.codegpt.predictions.CodeSuggestionDiffViewer
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
import ee.carlrobert.codegpt.settings.service.FeatureType
import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.codegpt.settings.service.ServiceType
import ee.carlrobert.codegpt.settings.service.ServiceType.INCEPTION
import ee.carlrobert.codegpt.settings.service.ServiceType.PROXYAI
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings
import ee.carlrobert.codegpt.treesitter.CodeCompletionParserFactory
import ee.carlrobert.codegpt.ui.OverlayUtil.showNotification
@ -27,7 +31,7 @@ import java.util.concurrent.atomic.AtomicBoolean
class CodeCompletionEventListener(
private val editor: Editor,
private val channel: ProducerScope<InlineCompletionElement>
private val channel: ProducerScope<InlineCompletionElement>,
) : CompletionEventListener<String> {
companion object {
@ -178,10 +182,12 @@ class CodeCompletionEventListener(
setLoading(false)
if (messageBuilder.isEmpty()) {
editor.project?.service<GrpcClientService>()?.getNextEdit(
NextEditCoordinator.requestNextEdit(
editor,
prefix + suffix,
runReadAction { editor.caretModel.offset })
runReadAction { editor.caretModel.offset },
false
)
}
}

View file

@ -9,7 +9,7 @@ import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.service
import ee.carlrobert.codegpt.CodeGPTKeys
import ee.carlrobert.codegpt.codecompletions.edit.GrpcClientService
import ee.carlrobert.codegpt.codecompletions.edit.NextEditCoordinator
import ee.carlrobert.codegpt.predictions.CodeSuggestionDiffViewer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -32,23 +32,23 @@ class CodeCompletionInsertHandler : InlineCompletionInsertHandler {
val prefix = editor.document.text.substring(0, caretOffset)
val suffix = editor.document.text.substring(caretOffset)
CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
editor.project?.service<GrpcClientService>()
?.getNextEdit(
editor,
prefix + remainingCompletion.partialCompletion + suffix,
caretOffset + remainingCompletion.partialCompletion.length,
true
)
NextEditCoordinator.requestNextEdit(
editor,
prefix + remainingCompletion.partialCompletion + suffix,
caretOffset + remainingCompletion.partialCompletion.length,
true
)
}
return
} else {
if (CodeGPTKeys.REMAINING_PREDICTION_RESPONSE.get(editor) == null) {
val caretOffset = runReadAction { editor.caretModel.offset }
CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
editor.project?.service<GrpcClientService>()?.getNextEdit(
NextEditCoordinator.requestNextEdit(
editor,
editor.document.text,
caretOffset,
false
)
}
return
@ -64,4 +64,4 @@ class CodeCompletionInsertHandler : InlineCompletionInsertHandler {
}
}
}
}
}

View file

@ -13,6 +13,7 @@ import ee.carlrobert.codegpt.settings.service.custom.CustomServicesSettings
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettingsState
import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings
import ee.carlrobert.llm.client.inception.request.InceptionFIMRequest
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest
import ee.carlrobert.llm.client.ollama.completion.request.OllamaCompletionRequest
import ee.carlrobert.llm.client.ollama.completion.request.OllamaParameters
@ -237,6 +238,16 @@ object CodeCompletionRequestFactory {
.build()
}
fun buildInceptionRequest(details: InfillRequest): InceptionFIMRequest {
val model = service<ModelSelectionService>().getModelForFeature(FeatureType.CODE_COMPLETION)
return InceptionFIMRequest.Builder()
.setPrompt(details.prefix)
.setSuffix(details.suffix)
.setModel(model)
.setStream(true)
.build()
}
private fun getLlamaInfillPromptTemplate(settings: LlamaSettingsState): InfillPromptTemplate {
if (settings.isUseCustomModel) {
return settings.localModelInfillPromptTemplate

View file

@ -5,6 +5,7 @@ import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestFactory.buildChatBasedFIMHttpRequest
import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestFactory.buildCustomRequest
import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestFactory.buildInceptionRequest
import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestFactory.buildLlamaRequest
import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestFactory.buildOllamaRequest
import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestFactory.buildOpenAIRequest
@ -17,6 +18,7 @@ import ee.carlrobert.codegpt.settings.service.ServiceType
import ee.carlrobert.codegpt.settings.service.ServiceType.*
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings
import ee.carlrobert.codegpt.settings.service.custom.CustomServicesSettings
import ee.carlrobert.codegpt.settings.service.inception.InceptionSettings
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
import ee.carlrobert.codegpt.settings.service.mistral.MistralSettings
import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings
@ -46,9 +48,11 @@ class CodeCompletionService(private val project: Project) {
.customServiceStateForFeatureType(FeatureType.CODE_COMPLETION)
.codeCompletionSettings
.codeCompletionsEnabled
MISTRAL -> MistralSettings.getCurrentState().isCodeCompletionsEnabled
LLAMA_CPP -> LlamaSettings.isCodeCompletionsPossible()
OLLAMA -> service<OllamaSettings>().state.codeCompletionsEnabled
INCEPTION -> service<InceptionSettings>().state.codeCompletionsEnabled
else -> false
}
@ -73,7 +77,11 @@ class CodeCompletionService(private val project: Project) {
val isChatBasedFIM =
customSettings.infillTemplate == InfillPromptTemplate.CHAT_COMPLETION
if (isChatBasedFIM) {
val credential = getCredential(CredentialKey.CustomServiceApiKeyById(requireNotNull(activeService.id)))
val credential = getCredential(
CredentialKey.CustomServiceApiKeyById(
requireNotNull(activeService.id)
)
)
createFactory(
CompletionClientProvider.getDefaultClientBuilder().build()
).newEventSource(
@ -107,7 +115,10 @@ class CodeCompletionService(private val project: Project) {
.getCompletionAsync(buildOllamaRequest(infillRequest), eventListener)
LLAMA_CPP -> CompletionClientProvider.getLlamaClient()
.getChatCompletionAsync(buildLlamaRequest(infillRequest), eventListener)
.getCodeCompletionAsync(buildLlamaRequest(infillRequest), eventListener)
INCEPTION -> CompletionClientProvider.getInceptionClient()
.getFimCompletionAsync(buildInceptionRequest(infillRequest), eventListener)
else -> throw IllegalArgumentException("Code completion not supported for ${selectedService.name}")
}

View file

@ -13,6 +13,7 @@ import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.codegpt.settings.service.ServiceType
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings
import ee.carlrobert.codegpt.settings.service.custom.CustomServicesSettings
import ee.carlrobert.codegpt.settings.service.inception.InceptionSettings
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
import ee.carlrobert.codegpt.settings.service.mistral.MistralSettings
import ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings
@ -117,6 +118,7 @@ class DebouncedCodeCompletionProvider : DebouncedInlineCompletionProvider() {
ServiceType.LLAMA_CPP -> LlamaSettings.isCodeCompletionsPossible()
ServiceType.OLLAMA -> service<OllamaSettings>().state.codeCompletionsEnabled
ServiceType.MISTRAL -> MistralSettings.getCurrentState().isCodeCompletionsEnabled
ServiceType.INCEPTION -> service<InceptionSettings>().state.codeCompletionsEnabled
ServiceType.ANTHROPIC,
ServiceType.GOOGLE,
null -> false

View file

@ -4,6 +4,7 @@ import com.intellij.codeInsight.inline.completion.elements.InlineCompletionEleme
import com.intellij.notification.NotificationType
import com.intellij.openapi.diagnostic.thisLogger
import ee.carlrobert.codegpt.codecompletions.CodeCompletionEventListener
import ee.carlrobert.llm.client.openai.completion.ErrorDetails
import ee.carlrobert.codegpt.ui.OverlayUtil
import ee.carlrobert.service.PartialCodeCompletionResponse
import io.grpc.Status
@ -45,10 +46,11 @@ class CodeCompletionStreamObserver(
NotificationType.ERROR
)
}
eventListener.onError(ErrorDetails(t?.message ?: "Code completion error"), t ?: Throwable())
channel.close(t)
}
override fun onCompleted() {
eventListener.onComplete(messageBuilder)
}
}
}

View file

@ -31,8 +31,7 @@ import java.util.concurrent.TimeUnit
class GrpcClientService(private val project: Project) : Disposable {
private var channel: ManagedChannel? = null
private var codeCompletionStub: CodeCompletionServiceImplGrpc.CodeCompletionServiceImplStub? =
null
private var codeCompletionStub: CodeCompletionServiceImplGrpc.CodeCompletionServiceImplStub? = null
private var codeCompletionObserver: CodeCompletionStreamObserver? = null
private var nextEditStub: NextEditServiceImplGrpc.NextEditServiceImplStub? = null
private var nextEditStreamObserver: NextEditStreamObserver? = null
@ -63,7 +62,7 @@ class GrpcClientService(private val project: Project) : Disposable {
caretOffset: Int,
addToQueue: Boolean = false,
) {
if (service<ModelSelectionService>().getServiceForFeature(FeatureType.CODE_COMPLETION) != ServiceType.PROXYAI
if (service<ModelSelectionService>().getServiceForFeature(FeatureType.NEXT_EDIT) != ServiceType.PROXYAI
|| !service<CodeGPTServiceSettings>().state.nextEditsEnabled
) {
return
@ -199,4 +198,4 @@ class GrpcClientService(private val project: Project) : Disposable {
}
channel = null
}
}
}

View file

@ -0,0 +1,130 @@
package ee.carlrobert.codegpt.codecompletions.edit
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import ee.carlrobert.codegpt.EncodingManager
import ee.carlrobert.codegpt.completions.CompletionClientProvider
import ee.carlrobert.codegpt.settings.models.ModelRegistry
import ee.carlrobert.codegpt.settings.service.FeatureType
import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.codegpt.settings.service.ServiceType
import ee.carlrobert.codegpt.toolwindow.chat.parser.SseMessageParser
import ee.carlrobert.codegpt.toolwindow.chat.parser.SearchReplace
import ee.carlrobert.codegpt.util.GitUtil
import ee.carlrobert.service.NextEditResponse
import ee.carlrobert.llm.client.inception.request.InceptionNextEditRequest
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionStandardMessage
import java.util.*
object InceptionNextEditRunner {
private val logger = thisLogger()
fun isEnabled(): Boolean {
return service<ModelSelectionService>().getServiceForFeature(FeatureType.NEXT_EDIT) == ServiceType.INCEPTION
}
fun run(editor: Editor, fileContent: String, caretOffset: Int, addToQueue: Boolean = false, onResult: (NextEditResponse) -> Unit) {
try {
val safeOffset = caretOffset.coerceIn(0, fileContent.length)
val codeWithCursor = buildString {
append(fileContent.substring(0, safeOffset))
append("<|cursor|>")
append(fileContent.substring(safeOffset))
}
val content = buildString {
append("<|recently_viewed_code_snippets|>\n")
append("<|/recently_viewed_code_snippets|>\n")
append("<|current_file_content|>\n")
append(fileContent)
append("\n<|code_to_edit|>\n")
append(codeWithCursor)
append("\n<|/code_to_edit|>")
append("<|/current_file_content|>\n")
append("<|edit_diff_history|>\n")
append(buildEditDiffHistory(editor.project))
append("\n<|/edit_diff_history|>")
}
val message = OpenAIChatCompletionStandardMessage("user", content)
val request = InceptionNextEditRequest.Builder()
.setModel(ModelRegistry.MERCURY_CODER)
.setMessages(listOf(message))
.build()
val response = CompletionClientProvider.getInceptionClient().getNextEditCompletion(request)
val text = response.choices?.firstOrNull()?.message?.content ?: return
val next = extractNextRevision(text, fileContent)
val result = NextEditResponse.newBuilder()
.setId(UUID.randomUUID().toString())
.setOldRevision(fileContent)
.setNextRevision(next)
.build()
onResult(result)
} catch (ex: Exception) {
logger.error("Something went wrong while retrieving next edit completion", ex)
}
}
private fun extractNextRevision(message: String, source: String): String {
// If model returned a fenced full file, extract it directly
extractTripleBacktickCode(message)?.let { fenced ->
if (fenced.isNotBlank()) return fenced
}
val parser = SseMessageParser()
val segments = parser.parse(message)
var result = source
segments.forEach { seg ->
if (seg is SearchReplace) {
val search = seg.search.trim()
val replace = seg.replace
if (search.isNotEmpty() && result.contains(search)) {
result = result.replaceFirst(search, replace)
}
}
}
return result
}
private fun extractTripleBacktickCode(message: String): String? {
val fence = "```"
val start = message.indexOf(fence)
if (start == -1) return null
// Skip optional language id on the opening fence
var contentStart = start + fence.length
if (contentStart < message.length && message[contentStart] == '\n') {
contentStart += 1
} else {
val nl = message.indexOf('\n', contentStart)
if (nl != -1) contentStart = nl + 1
}
val end = message.indexOf(fence, contentStart)
if (end == -1) return null
return message.substring(contentStart, end).trim()
}
}
private fun buildEditDiffHistory(project: Project?): String {
if (project == null) return ""
val sb = StringBuilder()
// Unstaged/staged current changes first
try {
GitUtil.getCurrentChanges(project)?.let { diff ->
if (diff.isNotBlank()) {
sb.append(diff.trim()).append('\n')
}
}
} catch (_: Exception) {
// ignore
}
val combined = sb.toString().trim()
return service<EncodingManager>().truncateText(combined, 2048, true)
}

View file

@ -0,0 +1,65 @@
package ee.carlrobert.codegpt.codecompletions.edit
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import ee.carlrobert.codegpt.CodeGPTKeys
import ee.carlrobert.codegpt.predictions.CodeSuggestionDiffViewer
import ee.carlrobert.codegpt.settings.service.FeatureType
import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.codegpt.settings.service.ServiceType.INCEPTION
import ee.carlrobert.codegpt.settings.service.ServiceType.PROXYAI
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings
import ee.carlrobert.codegpt.settings.service.inception.InceptionSettings
object NextEditCoordinator {
fun requestNextEdit(
editor: Editor,
fileContent: String,
caretOffset: Int = runReadAction { editor.caretModel.offset },
addToQueue: Boolean = false,
) {
val provider = service<ModelSelectionService>().getServiceForFeature(FeatureType.NEXT_EDIT)
when (provider) {
PROXYAI -> {
if (!service<CodeGPTServiceSettings>().state.nextEditsEnabled) {
return
}
editor.project?.service<GrpcClientService>()?.getNextEdit(
editor,
fileContent,
caretOffset,
addToQueue
)
}
INCEPTION -> {
if (!service<InceptionSettings>().state.nextEditsEnabled) {
return
}
InceptionNextEditRunner.run(
editor,
fileContent,
caretOffset,
addToQueue
) { response ->
if (addToQueue) {
CodeGPTKeys.REMAINING_PREDICTION_RESPONSE.set(editor, response)
} else {
runInEdt {
if (editor.document.text == response.oldRevision) {
CodeSuggestionDiffViewer.displayInlineDiff(editor, response)
}
}
}
}
}
else -> null
}
}
}

View file

@ -33,6 +33,7 @@ interface CompletionRequestFactory {
ServiceType.MISTRAL -> MistralRequestFactory()
ServiceType.OLLAMA -> OllamaRequestFactory()
ServiceType.LLAMA_CPP -> LlamaRequestFactory()
ServiceType.INCEPTION -> InceptionRequestFactory()
}
}

View file

@ -0,0 +1,106 @@
package ee.carlrobert.codegpt.completions.factory
import com.intellij.openapi.components.service
import ee.carlrobert.codegpt.completions.*
import ee.carlrobert.codegpt.settings.prompts.CoreActionsState
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
import ee.carlrobert.codegpt.settings.service.FeatureType
import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.codegpt.util.EditorUtil
import ee.carlrobert.llm.client.inception.request.InceptionApplyRequest
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionStandardMessage
import ee.carlrobert.llm.completion.CompletionRequest
class InceptionRequestFactory : BaseRequestFactory() {
override fun createChatRequest(params: ChatCompletionParameters): OpenAIChatCompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(FeatureType.CHAT)
val messages = OpenAIRequestFactory.buildOpenAIMessages(
model = model,
callParameters = params
)
return OpenAIChatCompletionRequest.Builder(messages)
.setModel(model)
.setStream(true)
.build()
}
override fun createInlineEditRequest(params: InlineEditCompletionParameters): OpenAIChatCompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(FeatureType.INLINE_EDIT)
val prepared = prepareInlineEditPrompts(params)
val messages = OpenAIRequestFactory.buildInlineEditMessages(prepared, params.conversation)
return OpenAIChatCompletionRequest.Builder(messages)
.setModel(model)
.setStream(true)
.build()
}
override fun createAutoApplyRequest(params: AutoApplyParameters): CompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(FeatureType.AUTO_APPLY)
val prompt =
"<|original_code|>\n" + EditorUtil.getFileContent(params.destination) + "\n<|/original_code|>\n\n<|update_snippet|>\n// ... existing code ...\n" + params.source + "\n// ... existing code ...\n<|/update_snippet|>"
return InceptionApplyRequest.Builder()
.setModel(model)
.setMessages(
listOf(
OpenAIChatCompletionStandardMessage("user", prompt)
)
)
.build()
}
override fun createBasicCompletionRequest(
systemPrompt: String,
userPrompt: String,
maxTokens: Int,
stream: Boolean,
featureType: FeatureType
): CompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(featureType)
return OpenAIChatCompletionRequest.Builder(
listOf(
OpenAIChatCompletionStandardMessage("system", systemPrompt),
OpenAIChatCompletionStandardMessage("user", userPrompt)
)
)
.setModel(model)
.setStream(stream)
.build()
}
override fun createCommitMessageRequest(params: CommitMessageCompletionParameters): OpenAIChatCompletionRequest {
val model =
ModelSelectionService.getInstance().getModelForFeature(FeatureType.COMMIT_MESSAGE)
val (gitDiff, systemPrompt) = params
return OpenAIChatCompletionRequest.Builder(
listOf(
OpenAIChatCompletionStandardMessage("system", systemPrompt),
OpenAIChatCompletionStandardMessage("user", gitDiff)
)
)
.setModel(model)
.setStream(true)
.build()
}
override fun createLookupRequest(params: LookupCompletionParameters): OpenAIChatCompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(FeatureType.LOOKUP)
val (prompt) = params
val systemPrompt =
service<PromptsSettings>().state.coreActions.generateNameLookups.instructions
?: CoreActionsState.DEFAULT_GENERATE_NAME_LOOKUPS_PROMPT
return OpenAIChatCompletionRequest.Builder(
listOf(
OpenAIChatCompletionStandardMessage("system", systemPrompt),
OpenAIChatCompletionStandardMessage("user", prompt)
)
)
.setModel(model)
.setStream(false)
.build()
}
}

View file

@ -2,42 +2,28 @@ package ee.carlrobert.codegpt.completions.factory
import com.intellij.openapi.components.service
import ee.carlrobert.codegpt.completions.BaseRequestFactory
import ee.carlrobert.codegpt.completions.InlineEditCompletionParameters
import ee.carlrobert.codegpt.completions.ChatCompletionParameters
import ee.carlrobert.codegpt.completions.ConversationType
import ee.carlrobert.codegpt.completions.llama.LlamaModel
import ee.carlrobert.codegpt.completions.llama.PromptTemplate
import ee.carlrobert.codegpt.completions.InlineEditCompletionParameters
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings
import ee.carlrobert.codegpt.settings.prompts.FilteredPromptsService
import ee.carlrobert.codegpt.settings.prompts.PromptsSettings
import ee.carlrobert.codegpt.settings.prompts.addProjectPath
import ee.carlrobert.codegpt.settings.service.FeatureType
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest
import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionRequest
import ee.carlrobert.llm.client.openai.completion.request.OpenAIChatCompletionStandardMessage
class LlamaRequestFactory : BaseRequestFactory() {
override fun createChatRequest(params: ChatCompletionParameters): LlamaCompletionRequest {
val promptTemplate = getPromptTemplate()
var systemPrompt =
if (params.conversationType == ConversationType.FIX_COMPILE_ERRORS) {
service<PromptsSettings>().state.coreActions.fixCompileErrors.instructions
} else {
service<PromptsSettings>().state.personas.selectedPersona.let {
if (it.disabled) null else service<FilteredPromptsService>().getFilteredPersonaPrompt(
params.chatMode
).addProjectPath()
}
}
systemPrompt = systemPrompt?.let { service<FilteredPromptsService>().applyClickableLinks(it) }
val prompt = promptTemplate.buildPrompt(
systemPrompt,
getPromptWithFilesContext(params),
params.conversation.messages
override fun createChatRequest(params: ChatCompletionParameters): OpenAIChatCompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(FeatureType.CHAT)
val configuration = service<ConfigurationSettings>().state
return OpenAIChatCompletionRequest.Builder(
OpenAIRequestFactory.buildOpenAIMessages(model, params)
)
return buildLlamaRequest(prompt, promptTemplate.stopTokens, true)
.setModel(model)
.setStream(true)
.setMaxTokens(null)
.setMaxCompletionTokens(configuration.maxTokens)
.setTemperature(configuration.temperature.toDouble())
.build()
}
override fun createBasicCompletionRequest(
@ -46,46 +32,32 @@ class LlamaRequestFactory : BaseRequestFactory() {
maxTokens: Int,
stream: Boolean,
featureType: FeatureType
): LlamaCompletionRequest {
val promptTemplate = getPromptTemplate(featureType)
val finalPrompt =
promptTemplate.buildPrompt(systemPrompt, userPrompt, listOf())
return buildLlamaRequest(finalPrompt, emptyList(), stream)
}
override fun createInlineEditRequest(params: InlineEditCompletionParameters): LlamaCompletionRequest {
val prepared = prepareInlineEditPrompts(params)
val promptTemplate = getPromptTemplate(FeatureType.INLINE_EDIT)
val history = params.conversation?.messages?.filter { !it.response.isNullOrBlank() } ?: listOf()
val finalPrompt = promptTemplate.buildPrompt(prepared.systemPrompt, prepared.userPrompt, history)
return buildLlamaRequest(finalPrompt, emptyList(), stream = true)
}
private fun getPromptTemplate(featureType: FeatureType? = null): PromptTemplate {
val settings = service<LlamaSettings>().state
return if (settings.isUseCustomModel)
settings.localModelPromptTemplate
else
LlamaModel.findByHuggingFaceModel(settings.huggingFaceModel).promptTemplate
}
private fun buildLlamaRequest(
prompt: String,
stopTokens: List<String>,
stream: Boolean = false
): LlamaCompletionRequest {
val configSettings = service<ConfigurationSettings>().state
val llamaSettings = service<LlamaSettings>().state
return LlamaCompletionRequest.Builder(prompt)
.setN_predict(configSettings.maxTokens)
.setTemperature(configSettings.temperature.toDouble())
.setTop_k(llamaSettings.topK)
.setTop_p(llamaSettings.topP)
.setMin_p(llamaSettings.minP)
.setRepeat_penalty(llamaSettings.repeatPenalty)
.setStop(stopTokens)
): OpenAIChatCompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(featureType)
val configuration = service<ConfigurationSettings>().state
return OpenAIChatCompletionRequest.Builder(
listOf(
OpenAIChatCompletionStandardMessage("system", systemPrompt),
OpenAIChatCompletionStandardMessage("user", userPrompt)
)
)
.setModel(model)
.setStream(stream)
.setMaxTokens(null)
.setMaxCompletionTokens(maxTokens)
.setTemperature(configuration.temperature.toDouble())
.build()
}
override fun createInlineEditRequest(params: InlineEditCompletionParameters): OpenAIChatCompletionRequest {
val model = ModelSelectionService.getInstance().getModelForFeature(FeatureType.INLINE_EDIT)
val prepared = prepareInlineEditPrompts(params)
val messages = OpenAIRequestFactory.buildInlineEditMessages(prepared, params.conversation)
val configuration = service<ConfigurationSettings>().state
return OpenAIChatCompletionRequest.Builder(messages)
.setModel(model)
.setStream(true)
.setTemperature(configuration.temperature.toDouble())
.build()
}
}

View file

@ -77,5 +77,9 @@ object CredentialsStore {
data object MistralApiKey : CredentialKey() {
override val value: String = "MISTRAL_API_KEY"
}
data object InceptionApiKey : CredentialKey() {
override val value: String = "INCEPTION_API_KEY"
}
}
}

View file

@ -34,6 +34,8 @@ import com.intellij.util.ui.JBUI
import com.intellij.util.ui.components.BorderLayoutPanel
import ee.carlrobert.codegpt.CodeGPTKeys
import ee.carlrobert.codegpt.codecompletions.edit.GrpcClientService
import ee.carlrobert.codegpt.codecompletions.edit.NextEditCoordinator
import ee.carlrobert.codegpt.telemetry.ui.preferences.TelemetryConfigurable
import ee.carlrobert.service.NextEditResponse
import java.awt.BorderLayout
import java.awt.Dimension
@ -128,10 +130,11 @@ class CodeSuggestionDiffViewer(
popup.dispose()
application.executeOnPooledThread {
grpcService?.getNextEdit(
NextEditCoordinator.requestNextEdit(
mainEditor,
mainEditor.document.text,
runReadAction { mainEditor.caretModel.offset },
false
)
}
}
@ -194,8 +197,8 @@ class CodeSuggestionDiffViewer(
)
if (popup.isVisible && !popup.isDisposed) {
adjustPopupSize(popup, myEditor)
popup.setLocation(adjustedLocation)
adjustPopupSize(popup, myEditor)
}
}
}
@ -386,4 +389,4 @@ fun createSuggestionDiffPopup(content: JComponent): JBPopup {
.setCancelOnWindowDeactivation(false)
.setCancelOnOtherWindowOpen(false)
.createPopup()
}
}

View file

@ -12,7 +12,7 @@ import com.intellij.testFramework.LightVirtualFile
import com.intellij.util.application
import ee.carlrobert.codegpt.CodeGPTKeys
import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier
import ee.carlrobert.codegpt.codecompletions.edit.GrpcClientService
import ee.carlrobert.codegpt.codecompletions.edit.NextEditCoordinator
import ee.carlrobert.codegpt.util.EditorDiffUtil.createDiffRequest
import kotlin.coroutines.cancellation.CancellationException
@ -26,6 +26,7 @@ class PredictionService {
fun acceptPrediction(editor: Editor) {
val diffViewer = editor.getUserData(CodeGPTKeys.EDITOR_PREDICTION_DIFF_VIEWER)
if (diffViewer != null && diffViewer.isVisible()) {
diffViewer.applyChanges()
return
}
@ -36,10 +37,11 @@ class PredictionService {
try {
application.executeOnPooledThread {
CompletionProgressNotifier.update(project, true)
project.service<GrpcClientService>().getNextEdit(
NextEditCoordinator.requestNextEdit(
editor,
editor.document.text,
runReadAction { editor.caretModel.offset },
false
)
}
} catch (e: CancellationException) {
@ -57,4 +59,4 @@ class PredictionService {
service<DiffManager>().showDiff(project, diffRequest)
}
}
}
}

View file

@ -22,8 +22,12 @@ class TriggerCustomPredictionAction : EditorAction(Handler()), HintManagerImpl.A
private class Handler : EditorWriteActionHandler() {
override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) {
if (ModelSelectionService.getInstance()
.getServiceForFeature(FeatureType.CODE_COMPLETION) != ServiceType.PROXYAI
val nextEditModelProvider = ModelSelectionService.getInstance()
.getServiceForFeature(FeatureType.NEXT_EDIT)
if (!listOf(
ServiceType.PROXYAI,
ServiceType.INCEPTION
).contains(nextEditModelProvider)
) {
return
}

View file

@ -104,6 +104,10 @@ object LegacySettingsMigration {
ServiceType.MISTRAL -> {
ModelRegistry.DEVSTRAL_MEDIUM_2507
}
ServiceType.INCEPTION -> {
ModelRegistry.MERCURY_CODER
}
}
} catch (e: Exception) {
logger.warn("Failed to get legacy chat model for $serviceType", e)
@ -152,10 +156,14 @@ object LegacySettingsMigration {
ServiceType.MISTRAL -> {
ModelRegistry.CODESTRAL_LATEST
}
ServiceType.INCEPTION -> {
ModelRegistry.MERCURY_CODER
}
}
} catch (e: Exception) {
logger.warn("Failed to get legacy code model for $serviceType", e)
null
}
}
}
}

View file

@ -37,6 +37,7 @@ object ModelIcons {
ServiceType.OLLAMA -> Icons.Ollama
ServiceType.CUSTOM_OPENAI -> Icons.OpenAI
ServiceType.LLAMA_CPP -> Icons.Llama
ServiceType.INCEPTION -> Icons.Inception
}
}
}
}

View file

@ -101,6 +101,14 @@ class ModelRegistry {
FeatureType.CHAT, FeatureType.CODE_COMPLETION, FeatureType.AUTO_APPLY,
FeatureType.COMMIT_MESSAGE, FeatureType.INLINE_EDIT, FeatureType.LOOKUP
)
),
ServiceType.INCEPTION to ModelCapability(
ServiceType.INCEPTION,
setOf(
FeatureType.CODE_COMPLETION,
FeatureType.AUTO_APPLY,
FeatureType.NEXT_EDIT
)
)
)
@ -272,6 +280,7 @@ class ModelRegistry {
addAll(getLlamaModels())
addAll(getOllamaModels())
addAll(getCustomOpenAIModels())
addAll(getInceptionModels())
}
}
@ -283,6 +292,7 @@ class ModelRegistry {
addAll(getLlamaModels())
addAll(getCustomOpenAICodeModels())
addAll(getOllamaModels())
addAll(getInceptionModels())
}
}
@ -307,7 +317,16 @@ class ModelRegistry {
}
private fun getNextEditModels(): List<ModelSelection> {
return listOf(ModelSelection(ServiceType.PROXYAI, ZETA, "Zeta"))
return listOf(
ModelSelection(ServiceType.PROXYAI, ZETA, "Zeta"),
ModelSelection(ServiceType.INCEPTION, MERCURY_CODER, "Mercury Coder")
)
}
private fun getInceptionModels(): List<ModelSelection> {
return listOf(
ModelSelection(ServiceType.INCEPTION, MERCURY_CODER, "Mercury Coder")
)
}
fun getProxyAIChatModels(): List<ModelSelection> {
@ -604,9 +623,11 @@ class ModelRegistry {
// Llama.cpp default models
const val LLAMA_3_2_3B_INSTRUCT = "llama-3.2-3b-instruct"
const val MERCURY_CODER = "mercury-coder"
@JvmStatic
fun getInstance(): ModelRegistry {
return ApplicationManager.getApplication().getService(ModelRegistry::class.java)
}
}
}
}

View file

@ -202,7 +202,8 @@ class ModelSettingsForm(
private fun updateNextEditButtonState(codeCompletionProvider: ServiceType) {
val nextEditButton = modelButtons[FeatureType.NEXT_EDIT] ?: return
nextEditButton.isEnabled = codeCompletionProvider == ServiceType.PROXYAI
nextEditButton.isEnabled =
codeCompletionProvider == ServiceType.PROXYAI || codeCompletionProvider == ServiceType.INCEPTION
}
fun isModified(): Boolean {
@ -312,4 +313,4 @@ class ModelSettingsForm(
override fun dispose() {
messageBusConnection.disconnect()
}
}
}

View file

@ -68,7 +68,8 @@ class SettingsModelComboBoxAction(
ServiceType.OPENAI,
ServiceType.CUSTOM_OPENAI,
ServiceType.GOOGLE,
ServiceType.MISTRAL
ServiceType.MISTRAL,
ServiceType.INCEPTION
)
val hasCloudProviders = cloudProviders.any { groupedModels.containsKey(it) }
@ -245,4 +246,4 @@ class SettingsModelComboBoxAction(
val llamaModel = LlamaModel.findByHuggingFaceModel(huggingFaceModel)
return "${llamaModel.label} (${huggingFaceModel.parameterSize}B) / Q${huggingFaceModel.quantization}"
}
}
}

View file

@ -0,0 +1,35 @@
package ee.carlrobert.codegpt.settings.service
import com.intellij.openapi.options.Configurable
import ee.carlrobert.codegpt.credentials.CredentialsStore
import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.InceptionApiKey
import ee.carlrobert.codegpt.settings.service.inception.InceptionSettingsForm
import javax.swing.JComponent
class InceptionServiceConfigurable : Configurable {
private lateinit var component: InceptionSettingsForm
override fun getDisplayName(): String {
return "ProxyAI: Inception Service"
}
override fun createComponent(): JComponent {
component = InceptionSettingsForm()
component.setApiKey(CredentialsStore.getCredential(InceptionApiKey))
return component.getForm()
}
override fun isModified(): Boolean {
return component.getApiKey() != CredentialsStore.getCredential(InceptionApiKey)
}
override fun apply() {
CredentialsStore.setCredential(InceptionApiKey, component.getApiKey())
ModelReplacementDialog.showDialogIfNeeded(ServiceType.INCEPTION)
}
override fun reset() {
component.setApiKey(CredentialsStore.getCredential(InceptionApiKey))
}
}

View file

@ -39,6 +39,7 @@ class ServiceConfigurableComponent {
"Mistral" to MistralServiceConfigurable::class.java,
"LLaMA C/C++" to LlamaServiceConfigurable::class.java,
"Ollama" to OllamaSettingsConfigurable::class.java,
"Inception" to InceptionServiceConfigurable::class.java,
).entries.forEach { (name, configurableClass) ->
formBuilder.addComponent(ActionLink(name) {
val context = service<DataManager>().getDataContext(it.source as ActionLink)
@ -47,4 +48,4 @@ class ServiceConfigurableComponent {
})
}
}
}
}

View file

@ -0,0 +1,15 @@
package ee.carlrobert.codegpt.settings.service.inception
import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.SimplePersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
@State(name = "CodeGPT_InceptionSettings", storages = [Storage("CodeGPT_InceptionSettings.xml")])
class InceptionSettings : SimplePersistentStateComponent<InceptionSettingsState>(InceptionSettingsState())
class InceptionSettingsState : BaseState() {
var codeCompletionsEnabled by property(true)
var nextEditsEnabled by property(true)
}

View file

@ -0,0 +1,22 @@
package ee.carlrobert.codegpt.settings.service.inception
import com.intellij.ui.components.JBPasswordField
import com.intellij.util.ui.FormBuilder
import javax.swing.JComponent
import javax.swing.JPanel
class InceptionSettingsForm {
private val apiKeyField = JBPasswordField()
private val panel: JPanel = FormBuilder.createFormBuilder()
.addLabeledComponent("API Key:", apiKeyField, 1, false)
.addComponentFillVertically(JPanel(), 0)
.panel
fun getForm(): JComponent = panel
fun getApiKey(): String? = String(apiKeyField.password)
fun setApiKey(value: String?) {
apiKeyField.text = value ?: ""
}
}

View file

@ -105,15 +105,6 @@ class ResponseEditorPanel(
replaceEditor(oldEditor, newState.editor)
}
fun removeCurrentEditor() {
runInEdt {
removeAll()
stateManager.clearCurrentState()
revalidate()
repaint()
}
}
fun applyCodeAsync(content: String, virtualFile: VirtualFile, editor: EditorEx, headerPanel: DefaultHeaderPanel? = null) {
val eventSource = CompletionRequestService.getInstance().autoApplyAsync(
AutoApplyParameters(content, virtualFile),

View file

@ -12,6 +12,9 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.readText
import com.intellij.ui.components.AnActionLink
import com.intellij.util.ui.JBUI
import ee.carlrobert.codegpt.settings.service.FeatureType
import ee.carlrobert.codegpt.settings.service.ModelSelectionService
import ee.carlrobert.codegpt.settings.service.ServiceType.INCEPTION
import ee.carlrobert.codegpt.util.EditorUtil
import javax.swing.JComponent
@ -33,6 +36,15 @@ class AutoApplyAction(
}
override fun update(e: AnActionEvent) {
val autoApplyProvider =
ModelSelectionService.getInstance().getServiceForFeature(FeatureType.AUTO_APPLY)
if (autoApplyProvider == INCEPTION) {
anActionLink.text = "Apply"
anActionLink.isEnabled = false
anActionLink.toolTipText = "Auto Apply is temporarily disabled for Inception provider"
return
}
if (virtualFile != null) {
anActionLink.text = "Apply"
anActionLink.isEnabled = true

View file

@ -43,7 +43,7 @@ object GitUtil {
.filter { change ->
change.virtualFile?.let { !it.fileType.isBinary } ?: false
}
.sortedBy { it.virtualFile?.timeStamp }
.sortedByDescending { it.virtualFile?.timeStamp }
val patches = IdeaTextPatchBuilder.buildPatch(
project, changes, repoRootPath, false, true
@ -52,7 +52,7 @@ object GitUtil {
UnifiedDiffWriter.write(
null, repoRootPath, patches, diffWriter, "\n\n", null, null
)
diffWriter.toString().cleanDiff().truncateText(1024, false)
diffWriter.toString().cleanDiff().truncateText(1024, true)
} catch (e: VcsException) {
logger.error("Failed to get git context", e)
null

View file

@ -56,6 +56,9 @@
<applicationConfigurable id="settings.codegpt.services.ollama" parentId="settings.codegpt.services"
displayName="Ollama (Offline)"
instance="ee.carlrobert.codegpt.settings.service.ollama.OllamaSettingsConfigurable"/>
<applicationConfigurable id="settings.codegpt.services.inception" parentId="settings.codegpt.services"
displayName="Inception"
instance="ee.carlrobert.codegpt.settings.service.InceptionServiceConfigurable"/>
<applicationConfigurable id="settings.codegpt.models" parentId="settings.codegpt" bundle="messages.codegpt"
key="settings.models.displayName"
instance="ee.carlrobert.codegpt.settings.models.ModelSettingsConfigurable"/>
@ -87,6 +90,7 @@
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.service.mistral.MistralSettings"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.service.llama.LlamaSettings"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.service.ollama.OllamaSettings"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.service.inception.InceptionSettings"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.models.ModelSettings"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.IncludedFilesSettings"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.advanced.AdvancedSettings"/>

View file

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 28 28" fill="none">
<g clip-path="url(#svg1378540956_510_clip0_1_1506)">
<path d="M17.0547 0.372066H8.52652L-0.00165176 8.90024V17.4284H8.52652V8.90024H17.0547V0.372066Z" fill="#1A1C20"/>
<path d="M10.1992 27.6279H18.7274L27.2556 19.0998V10.5716H18.7274V19.0998H10.1992V27.6279Z" fill="#1A1C20"/>
</g>
<defs>
<clipPath id="svg1378540956_510_clip0_1_1506">
<rect width="27.2559" height="27.2559" fill="white" transform="translate(0 0.37207)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 577 B

View file

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 28 28" fill="none">
<g clip-path="url(#svg1378540956_510_clip0_1_1506)">
<path d="M17.0547 0.372066H8.52652L-0.00165176 8.90024V17.4284H8.52652V8.90024H17.0547V0.372066Z" fill="white"/>
<path d="M10.1992 27.6279H18.7274L27.2556 19.0998V10.5716H18.7274V19.0998H10.1992V27.6279Z" fill="white"/>
</g>
<defs>
<clipPath id="svg1378540956_510_clip0_1_1506">
<rect width="27.2559" height="27.2559" fill="white" transform="translate(0 0.37207)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 573 B

View file

@ -254,6 +254,7 @@ service.anthropic.title=Anthropic
service.azure.title=Azure
service.google.title=Google
service.mistral.title=Mistral
service.inception.title=Inception Labs
service.llama.title=LLaMA C/C++
service.ollama.title=Ollama
validation.error.model.notExists='%s' is not available, please select another model

View file

@ -77,31 +77,31 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() {
val conversation = ConversationService.getInstance().startConversation(project)
conversation.addMessage(Message("Ping", "Pong"))
expectLlama(StreamHttpExchange { request: RequestEntity ->
assertThat(request.uri.path).isEqualTo("/completion")
assertThat(request.uri.path).isEqualTo("/v1/chat/completions")
val guidelines = getResourceContent("/prompts/persona/psi-navigation-guidelines.txt")
val expectedSystem = "TEST_SYSTEM_PROMPT\n$guidelines"
assertThat(request.body)
.extracting(
"prompt",
"n_predict",
"stream"
"model",
"messages"
)
.containsExactly(
LLAMA.buildPrompt(
expectedSystem,
"TEST_PROMPT",
conversation.messages
),
99,
true
HuggingFaceModel.CODE_LLAMA_7B_Q4.code,
listOf(
mapOf("role" to "system", "content" to expectedSystem),
mapOf("role" to "user", "content" to "Ping"),
mapOf("role" to "assistant", "content" to "Pong"),
mapOf("role" to "user", "content" to "TEST_PROMPT")
)
)
listOf<String?>(
jsonMapResponse("content", "Hel"),
jsonMapResponse("content", "lo!"),
listOf(
jsonMapResponse(
e("content", ""),
e("stop", true)
)
"choices",
jsonArray(jsonMap("delta", jsonMap("role", "assistant")))
),
jsonMapResponse("choices", jsonArray(jsonMap("delta", jsonMap("content", "Hel")))),
jsonMapResponse("choices", jsonArray(jsonMap("delta", jsonMap("content", "lo")))),
jsonMapResponse("choices", jsonArray(jsonMap("delta", jsonMap("content", "!"))))
)
})
val requestHandler =

View file

@ -115,15 +115,16 @@ class ModelRegistryTest : IntegrationTest() {
ServiceType.MISTRAL,
ServiceType.OLLAMA,
ServiceType.LLAMA_CPP,
ServiceType.CUSTOM_OPENAI
ServiceType.CUSTOM_OPENAI,
ServiceType.INCEPTION
)
assertThat(result).doesNotContain(ServiceType.ANTHROPIC, ServiceType.GOOGLE)
}
fun `test getProvidersForFeature with next edit returns proxyai only`() {
fun `test getProvidersForFeature with next edit returns proxyai and inception`() {
val result = modelRegistry.getProvidersForFeature(FeatureType.NEXT_EDIT)
assertThat(result).containsExactly(ServiceType.PROXYAI)
assertThat(result).containsExactlyInAnyOrder(ServiceType.PROXYAI, ServiceType.INCEPTION)
}
fun `test isFeatureSupportedByProvider with valid chat provider returns true`() {
@ -182,4 +183,4 @@ class ModelRegistryTest : IntegrationTest() {
assertThat(result).isNull()
}
}
}

View file

@ -401,41 +401,30 @@ class ChatToolWindowTabPanelTest : IntegrationTest() {
val conversation = ConversationService.getInstance().startConversation(project)
val panel = ChatToolWindowTabPanel(project, conversation)
expectLlama(StreamHttpExchange { request: RequestEntity ->
assertThat(request.uri.path).isEqualTo("/completion")
assertThat(request.uri.path).isEqualTo("/v1/chat/completions")
val expectedSystem = getResourceContent("/prompts/persona/psi-navigation-guidelines.txt").let { g ->
"TEST_SYSTEM_PROMPT\n$g"
}
assertThat(request.body)
.extracting(
"prompt",
"n_predict",
"stream",
"temperature",
"top_k",
"top_p",
"min_p",
"repeat_penalty"
"model",
"messages"
)
.containsExactly(
LLAMA.buildPrompt(
(getResourceContent("/prompts/persona/psi-navigation-guidelines.txt").let { g ->
"TEST_SYSTEM_PROMPT\n$g"
}),
"TEST_PROMPT",
conversation.messages
),
configurationState.maxTokens,
true,
configurationState.temperature.toDouble(),
llamaSettings.topK,
llamaSettings.topP,
llamaSettings.minP,
llamaSettings.repeatPenalty
HuggingFaceModel.CODE_LLAMA_7B_Q4.code,
listOf(
mapOf("role" to "system", "content" to expectedSystem),
mapOf("role" to "user", "content" to "TEST_PROMPT")
)
)
listOf<String?>(
jsonMapResponse("content", "Hel"),
jsonMapResponse("content", "lo!"),
listOf(
jsonMapResponse(
e("content", ""),
e("stop", true)
)
"choices",
jsonArray(jsonMap("delta", jsonMap("role", "assistant")))
),
jsonMapResponse("choices", jsonArray(jsonMap("delta", jsonMap("content", "Hel")))),
jsonMapResponse("choices", jsonArray(jsonMap("delta", jsonMap("content", "lo")))),
jsonMapResponse("choices", jsonArray(jsonMap("delta", jsonMap("content", "!"))))
)
})