Skip to content

Commit

Permalink
Add Claude provider and templates for chat and code (#55)
Browse files Browse the repository at this point in the history
* feat: Add provider settings
* feat: Add Claude provider
* feat: Add Claude templates
* refactor: Setting input sensitivity
* fix: Back text after read code block
* fix: Add missing system message for ollama fim
  • Loading branch information
Palm1r authored Dec 23, 2024
1 parent d8ef9d0 commit d04e5bc
Show file tree
Hide file tree
Showing 28 changed files with 690 additions and 63 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ add_qtc_plugin(QodeAssist
templates/Alpaca.hpp
templates/Llama2.hpp
providers/Providers.hpp
templates/Claude.hpp
providers/OllamaProvider.hpp providers/OllamaProvider.cpp
providers/LMStudioProvider.hpp providers/LMStudioProvider.cpp
providers/OpenAICompatProvider.hpp providers/OpenAICompatProvider.cpp
providers/OpenRouterAIProvider.hpp providers/OpenRouterAIProvider.cpp
providers/ClaudeProvider.hpp providers/ClaudeProvider.cpp
QodeAssist.qrc
LSPCompletion.hpp
LLMSuggestion.hpp LLMSuggestion.cpp
Expand Down
2 changes: 1 addition & 1 deletion ChatView/ClientInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void ClientInterface::sendMessage(const QString &message, bool includeCurrentFil
config.url = QString("%1%2").arg(Settings::generalSettings().caUrl(), provider->chatEndpoint());
config.providerRequest = providerRequest;
config.multiLineCompletion = false;
config.apiKey = Settings::chatAssistantSettings().apiKey();
config.apiKey = provider->apiKey();

QJsonObject request;
request["id"] = QUuid::createUuid().toString();
Expand Down
13 changes: 13 additions & 0 deletions CodeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ QString CodeHandler::processText(QString text)
}
}

if (!pendingComments.isEmpty()) {
QStringList commentLines = pendingComments.split('\n');
QString commentPrefix = getCommentPrefix(currentLanguage);

for (const QString &commentLine : commentLines) {
if (!commentLine.trimmed().isEmpty()) {
result += commentPrefix + " " + commentLine.trimmed() + "\n";
} else {
result += "\n";
}
}
}

return result;
}

Expand Down
2 changes: 1 addition & 1 deletion LLMClientInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
Settings::generalSettings().ccUrl(),
promptTemplate->type() == LLMCore::TemplateType::Fim ? provider->completionEndpoint()
: provider->chatEndpoint()));
config.apiKey = Settings::codeCompletionSettings().apiKey();
config.apiKey = provider->apiKey();

config.providerRequest
= {{"model", Settings::generalSettings().ccModel()},
Expand Down
98 changes: 56 additions & 42 deletions QodeAssistClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,48 +71,62 @@ void QodeAssistClient::openDocument(TextEditor::TextDocument *document)
return;

Client::openDocument(document);
connect(document,
&TextDocument::contentsChangedWithPosition,
this,
[this, document](int position, int charsRemoved, int charsAdded) {
Q_UNUSED(charsRemoved)
if (!Settings::codeCompletionSettings().autoCompletion())
return;

auto project = ProjectManager::projectForFile(document->filePath());
if (!isEnabled(project))
return;

auto textEditor = BaseTextEditor::currentTextEditor();
if (!textEditor || textEditor->document() != document)
return;

if (Settings::codeCompletionSettings().useProjectChangesCache())
ChangesManager::instance().addChange(document,
position,
charsRemoved,
charsAdded);

TextEditorWidget *widget = textEditor->editorWidget();
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
return;
const int cursorPosition = widget->textCursor().position();
if (cursorPosition < position || cursorPosition > position + charsAdded)
return;

m_recentCharCount += charsAdded;

if (m_typingTimer.elapsed()
> Settings::codeCompletionSettings().autoCompletionTypingInterval()) {
m_recentCharCount = charsAdded;
m_typingTimer.restart();
}

if (m_recentCharCount
> Settings::codeCompletionSettings().autoCompletionCharThreshold()) {
scheduleRequest(widget);
}
});
connect(
document,
&TextDocument::contentsChangedWithPosition,
this,
[this, document](int position, int charsRemoved, int charsAdded) {
if (!Settings::codeCompletionSettings().autoCompletion())
return;

auto project = ProjectManager::projectForFile(document->filePath());
if (!isEnabled(project))
return;

auto textEditor = BaseTextEditor::currentTextEditor();
if (!textEditor || textEditor->document() != document)
return;

if (Settings::codeCompletionSettings().useProjectChangesCache())
ChangesManager::instance().addChange(document, position, charsRemoved, charsAdded);

TextEditorWidget *widget = textEditor->editorWidget();
if (widget->isReadOnly() || widget->multiTextCursor().hasMultipleCursors())
return;

const int cursorPosition = widget->textCursor().position();
if (cursorPosition < position || cursorPosition > position + charsAdded)
return;

if (charsRemoved > 0 || charsAdded <= 0) {
m_recentCharCount = 0;
m_typingTimer.restart();
return;
}

QTextCursor cursor = widget->textCursor();
cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
QString lastChar = cursor.selectedText();

if (lastChar.isEmpty() || lastChar[0].isPunct()) {
m_recentCharCount = 0;
m_typingTimer.restart();
return;
}

m_recentCharCount += charsAdded;

if (m_typingTimer.elapsed()
> Settings::codeCompletionSettings().autoCompletionTypingInterval()) {
m_recentCharCount = charsAdded;
m_typingTimer.restart();
}

if (m_recentCharCount
> Settings::codeCompletionSettings().autoCompletionCharThreshold()) {
scheduleRequest(widget);
}
});
}

bool QodeAssistClient::canOpenProject(ProjectExplorer::Project *project)
Expand Down
1 change: 1 addition & 0 deletions llmcore/MessageBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ void QodeAssist::LLMCore::MessageBuilder::saveTo(QJsonObject &request, Providers

if (api == ProvidersApi::Ollama) {
if (m_promptTemplate->type() == TemplateType::Fim) {
request["system"] = m_systemMessage;
m_promptTemplate->prepareRequest(request, context);
} else {
QJsonArray messages;
Expand Down
2 changes: 1 addition & 1 deletion llmcore/MessageBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ enum class MessageRole { System, User, Assistant };

enum class OllamaFormat { Messages, Completions };

enum class ProvidersApi { Ollama, OpenAI };
enum class ProvidersApi { Ollama, OpenAI, Claude };

static const QString ROLE_SYSTEM = "system";
static const QString ROLE_USER = "user";
Expand Down
5 changes: 4 additions & 1 deletion llmcore/Provider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@

#pragma once

#include <QString>
#include <utils/environment.h>
#include <QNetworkRequest>
#include <QString>

#include "PromptTemplate.hpp"
#include "RequestType.hpp"
Expand All @@ -45,6 +46,8 @@ class Provider
virtual bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) = 0;
virtual QList<QString> getInstalledModels(const QString &url) = 0;
virtual QList<QString> validateRequest(const QJsonObject &request, TemplateType type) = 0;
virtual QString apiKey() const = 0;
virtual void prepareNetworkRequest(QNetworkRequest &networkRequest) const = 0;
};

} // namespace QodeAssist::LLMCore
12 changes: 1 addition & 11 deletions llmcore/RequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void RequestHandler::sendLLMRequest(const LLMConfig &config, const QJsonObject &
QJsonDocument(config.providerRequest).toJson(QJsonDocument::Indented))));

QNetworkRequest networkRequest(config.url);
prepareNetworkRequest(networkRequest, config.apiKey);
config.provider->prepareNetworkRequest(networkRequest);

QNetworkReply *reply = m_manager->post(networkRequest,
QJsonDocument(config.providerRequest).toJson());
Expand Down Expand Up @@ -108,16 +108,6 @@ bool RequestHandler::cancelRequest(const QString &id)
return false;
}

void RequestHandler::prepareNetworkRequest(
QNetworkRequest &networkRequest, const QString &apiKey) const
{
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

if (!apiKey.isEmpty()) {
networkRequest.setRawHeader("Authorization", QString("Bearer %1").arg(apiKey).toUtf8());
}
}

bool RequestHandler::processSingleLineCompletion(
QNetworkReply *reply,
const QJsonObject &request,
Expand Down
1 change: 0 additions & 1 deletion llmcore/RequestHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ class RequestHandler : public QObject
QMap<QString, QNetworkReply *> m_activeRequests;
QMap<QNetworkReply *, QString> m_accumulatedResponses;

void prepareNetworkRequest(QNetworkRequest &networkRequest, const QString &apiKey) const;
bool processSingleLineCompletion(QNetworkReply *reply,
const QJsonObject &request,
const QString &accumulatedResponse,
Expand Down
Loading

0 comments on commit d04e5bc

Please sign in to comment.