feat: Add Claude extended thinking (#254)

* feat: Add Claude extended thinking
* fix: Set 1.0 temperature for thinking mode
This commit is contained in:
Petr Mironychev
2025-11-12 18:33:15 +01:00
committed by GitHub
parent 89797639cf
commit 161d77ac04
23 changed files with 745 additions and 40 deletions

View File

@ -137,4 +137,68 @@ private:
QString m_result;
};
class ThinkingContent : public ContentBlock
{
Q_OBJECT
public:
explicit ThinkingContent(const QString &thinking = QString(), const QString &signature = QString())
: ContentBlock()
, m_thinking(thinking)
, m_signature(signature)
{}
QString type() const override { return "thinking"; }
QString thinking() const { return m_thinking; }
QString signature() const { return m_signature; }
void appendThinking(const QString &text) { m_thinking += text; }
void setThinking(const QString &text) { m_thinking = text; }
void setSignature(const QString &signature) { m_signature = signature; }
QJsonValue toJson(ProviderFormat format) const override
{
Q_UNUSED(format);
// Only include signature field if it's not empty
// Empty signature is rejected by API with "Invalid signature" error
// In streaming mode, signature is not provided, so we omit the field entirely
QJsonObject obj{{"type", "thinking"}, {"thinking", m_thinking}};
if (!m_signature.isEmpty()) {
obj["signature"] = m_signature;
}
return obj;
}
private:
QString m_thinking;
QString m_signature;
};
class RedactedThinkingContent : public ContentBlock
{
Q_OBJECT
public:
explicit RedactedThinkingContent(const QString &signature = QString())
: ContentBlock()
, m_signature(signature)
{}
QString type() const override { return "redacted_thinking"; }
QString signature() const { return m_signature; }
void setSignature(const QString &signature) { m_signature = signature; }
QJsonValue toJson(ProviderFormat format) const override
{
Q_UNUSED(format);
// Only include signature field if it's not empty
// Empty signature is rejected by API with "Invalid signature" error
QJsonObject obj{{"type", "redacted_thinking"}};
if (!m_signature.isEmpty()) {
obj["signature"] = m_signature;
}
return obj;
}
private:
QString m_signature;
};
} // namespace QodeAssist::LLMCore

View File

@ -28,6 +28,9 @@ struct Message
{
QString role;
QString content;
QString signature;
bool isThinking = false;
bool isRedacted = false;
// clang-format off
bool operator==(const Message&) const = default;

View File

@ -65,6 +65,7 @@ public:
= 0;
virtual bool supportsTools() const { return false; };
virtual bool supportThinking() const { return false; };
virtual void cancelRequest(const RequestID &requestId);
@ -92,6 +93,9 @@ signals:
const QString &toolName,
const QString &result);
void continuationStarted(const QodeAssist::LLMCore::RequestID &requestId);
void thinkingBlockReceived(
const QString &requestId, const QString &thinking, const QString &signature);
void redactedThinkingBlockReceived(const QString &requestId, const QString &signature);
protected:
QJsonObject parseEventLine(const QString &line);