mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-02-22 23:13:21 -05:00
fix: Add signature to chat history
This commit is contained in:
@ -131,7 +131,9 @@ void ChatModel::addMessage(
|
|||||||
ChatRole role,
|
ChatRole role,
|
||||||
const QString &id,
|
const QString &id,
|
||||||
const QList<Context::ContentFile> &attachments,
|
const QList<Context::ContentFile> &attachments,
|
||||||
const QList<ImageAttachment> &images)
|
const QList<ImageAttachment> &images,
|
||||||
|
bool isRedacted,
|
||||||
|
const QString &signature)
|
||||||
{
|
{
|
||||||
QString fullContent = content;
|
QString fullContent = content;
|
||||||
if (!attachments.isEmpty()) {
|
if (!attachments.isEmpty()) {
|
||||||
@ -148,12 +150,16 @@ void ChatModel::addMessage(
|
|||||||
lastMessage.content = content;
|
lastMessage.content = content;
|
||||||
lastMessage.attachments = attachments;
|
lastMessage.attachments = attachments;
|
||||||
lastMessage.images = images;
|
lastMessage.images = images;
|
||||||
|
lastMessage.isRedacted = isRedacted;
|
||||||
|
lastMessage.signature = signature;
|
||||||
emit dataChanged(index(m_messages.size() - 1), index(m_messages.size() - 1));
|
emit dataChanged(index(m_messages.size() - 1), index(m_messages.size() - 1));
|
||||||
} else {
|
} else {
|
||||||
beginInsertRows(QModelIndex(), m_messages.size(), m_messages.size());
|
beginInsertRows(QModelIndex(), m_messages.size(), m_messages.size());
|
||||||
Message newMessage{role, content, id};
|
Message newMessage{role, content, id};
|
||||||
newMessage.attachments = attachments;
|
newMessage.attachments = attachments;
|
||||||
newMessage.images = images;
|
newMessage.images = images;
|
||||||
|
newMessage.isRedacted = isRedacted;
|
||||||
|
newMessage.signature = signature;
|
||||||
m_messages.append(newMessage);
|
m_messages.append(newMessage);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,9 @@ public:
|
|||||||
ChatRole role,
|
ChatRole role,
|
||||||
const QString &id,
|
const QString &id,
|
||||||
const QList<Context::ContentFile> &attachments = {},
|
const QList<Context::ContentFile> &attachments = {},
|
||||||
const QList<ImageAttachment> &images = {});
|
const QList<ImageAttachment> &images = {},
|
||||||
|
bool isRedacted = false,
|
||||||
|
const QString &signature = QString());
|
||||||
Q_INVOKABLE void clear();
|
Q_INVOKABLE void clear();
|
||||||
Q_INVOKABLE QList<MessagePart> processMessageContent(const QString &content) const;
|
Q_INVOKABLE QList<MessagePart> processMessageContent(const QString &content) const;
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,11 @@ QJsonObject ChatSerializer::serializeMessage(const ChatModel::Message &message,
|
|||||||
messageObj["role"] = static_cast<int>(message.role);
|
messageObj["role"] = static_cast<int>(message.role);
|
||||||
messageObj["content"] = message.content;
|
messageObj["content"] = message.content;
|
||||||
messageObj["id"] = message.id;
|
messageObj["id"] = message.id;
|
||||||
messageObj["isRedacted"] = message.isRedacted;
|
|
||||||
|
if (message.isRedacted) {
|
||||||
|
messageObj["isRedacted"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!message.signature.isEmpty()) {
|
if (!message.signature.isEmpty()) {
|
||||||
messageObj["signature"] = message.signature;
|
messageObj["signature"] = message.signature;
|
||||||
}
|
}
|
||||||
@ -167,8 +171,11 @@ bool ChatSerializer::deserializeChat(ChatModel *model, const QJsonObject &json,
|
|||||||
model->setLoadingFromHistory(true);
|
model->setLoadingFromHistory(true);
|
||||||
|
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
model->addMessage(message.content, message.role, message.id, message.attachments, message.images);
|
model->addMessage(message.content, message.role, message.id, message.attachments, message.images, message.isRedacted, message.signature);
|
||||||
LOG_MESSAGE(QString("Loaded message with %1 image(s)").arg(message.images.size()));
|
LOG_MESSAGE(QString("Loaded message with %1 image(s), isRedacted=%2, signature length=%3")
|
||||||
|
.arg(message.images.size())
|
||||||
|
.arg(message.isRedacted)
|
||||||
|
.arg(message.signature.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
model->setLoadingFromHistory(false);
|
model->setLoadingFromHistory(false);
|
||||||
|
|||||||
@ -44,6 +44,11 @@ public:
|
|||||||
if (msg.role == "system") continue;
|
if (msg.role == "system") continue;
|
||||||
|
|
||||||
if (msg.isThinking) {
|
if (msg.isThinking) {
|
||||||
|
// Claude API requires signature for thinking blocks
|
||||||
|
if (msg.signature.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonArray content;
|
QJsonArray content;
|
||||||
QJsonObject thinkingBlock;
|
QJsonObject thinkingBlock;
|
||||||
thinkingBlock["type"] = msg.isRedacted ? "redacted_thinking" : "thinking";
|
thinkingBlock["type"] = msg.isRedacted ? "redacted_thinking" : "thinking";
|
||||||
@ -57,9 +62,7 @@ public:
|
|||||||
if (!msg.isRedacted) {
|
if (!msg.isRedacted) {
|
||||||
thinkingBlock["thinking"] = thinkingText;
|
thinkingBlock["thinking"] = thinkingText;
|
||||||
}
|
}
|
||||||
if (!msg.signature.isEmpty()) {
|
thinkingBlock["signature"] = msg.signature;
|
||||||
thinkingBlock["signature"] = msg.signature;
|
|
||||||
}
|
|
||||||
content.append(thinkingBlock);
|
content.append(thinkingBlock);
|
||||||
|
|
||||||
messages.append(QJsonObject{{"role", "assistant"}, {"content", content}});
|
messages.append(QJsonObject{{"role", "assistant"}, {"content", content}});
|
||||||
|
|||||||
@ -46,36 +46,58 @@ public:
|
|||||||
QJsonObject content;
|
QJsonObject content;
|
||||||
QJsonArray parts;
|
QJsonArray parts;
|
||||||
|
|
||||||
if (!msg.content.isEmpty()) {
|
if (msg.isThinking) {
|
||||||
parts.append(QJsonObject{{"text", msg.content}});
|
if (!msg.content.isEmpty()) {
|
||||||
}
|
QJsonObject thinkingPart;
|
||||||
|
thinkingPart["text"] = msg.content;
|
||||||
if (msg.images && !msg.images->isEmpty()) {
|
thinkingPart["thought"] = true;
|
||||||
for (const auto &image : msg.images.value()) {
|
parts.append(thinkingPart);
|
||||||
QJsonObject imagePart;
|
|
||||||
|
|
||||||
if (image.isUrl) {
|
|
||||||
QJsonObject fileData;
|
|
||||||
fileData["mime_type"] = image.mediaType;
|
|
||||||
fileData["file_uri"] = image.data;
|
|
||||||
imagePart["file_data"] = fileData;
|
|
||||||
} else {
|
|
||||||
QJsonObject inlineData;
|
|
||||||
inlineData["mime_type"] = image.mediaType;
|
|
||||||
inlineData["data"] = image.data;
|
|
||||||
imagePart["inline_data"] = inlineData;
|
|
||||||
}
|
|
||||||
|
|
||||||
parts.append(imagePart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!msg.signature.isEmpty()) {
|
||||||
|
QJsonObject signaturePart;
|
||||||
|
signaturePart["thoughtSignature"] = msg.signature;
|
||||||
|
parts.append(signaturePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
content["role"] = "model";
|
||||||
|
} else {
|
||||||
|
if (!msg.content.isEmpty()) {
|
||||||
|
parts.append(QJsonObject{{"text", msg.content}});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.images && !msg.images->isEmpty()) {
|
||||||
|
for (const auto &image : msg.images.value()) {
|
||||||
|
QJsonObject imagePart;
|
||||||
|
|
||||||
|
if (image.isUrl) {
|
||||||
|
QJsonObject fileData;
|
||||||
|
fileData["mime_type"] = image.mediaType;
|
||||||
|
fileData["file_uri"] = image.data;
|
||||||
|
imagePart["file_data"] = fileData;
|
||||||
|
} else {
|
||||||
|
QJsonObject inlineData;
|
||||||
|
inlineData["mime_type"] = image.mediaType;
|
||||||
|
inlineData["data"] = image.data;
|
||||||
|
imagePart["inline_data"] = inlineData;
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.append(imagePart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString role = msg.role;
|
||||||
|
if (role == "assistant") {
|
||||||
|
role = "model";
|
||||||
|
}
|
||||||
|
|
||||||
|
content["role"] = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString role = msg.role;
|
|
||||||
if (role == "assistant") {
|
|
||||||
role = "model";
|
|
||||||
}
|
|
||||||
|
|
||||||
content["role"] = role;
|
|
||||||
content["parts"] = parts;
|
content["parts"] = parts;
|
||||||
contents.append(content);
|
contents.append(content);
|
||||||
}
|
}
|
||||||
@ -95,11 +117,15 @@ public:
|
|||||||
" },\n"
|
" },\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"role\": \"model\",\n"
|
" \"role\": \"model\",\n"
|
||||||
" \"parts\": [{\"text\": \"<assistant response>\"}]\n"
|
" \"parts\": [\n"
|
||||||
|
" {\"text\": \"<thinking>\", \"thought\": true},\n"
|
||||||
|
" {\"thoughtSignature\": \"<signature>\"},\n"
|
||||||
|
" {\"text\": \"<assistant response>\"}\n"
|
||||||
|
" ]\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
"}\n\n"
|
"}\n\n"
|
||||||
"Supports proper role mapping, including model/user roles.";
|
"Supports proper role mapping (model/user roles), images, and thinking blocks.";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSupportProvider(LLMCore::ProviderID id) const override
|
bool isSupportProvider(LLMCore::ProviderID id) const override
|
||||||
|
|||||||
Reference in New Issue
Block a user