chore: restructure llm plugin to be more coherent & fix various bugs in llm ui
C++ / fmt (pull_request) Failing after 6s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 9s
JS/TS / fmt (pull_request) Successful in 10s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Successful in 30s
Rust / build (pull_request) Successful in 49s
Python / verify (pull_request) Successful in 1m35s
Rust / fmt (pull_request) Successful in 36s
Rust / clippy (pull_request) Successful in 54s
C++ / fmt (pull_request) Failing after 6s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 9s
JS/TS / fmt (pull_request) Successful in 10s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Successful in 30s
Rust / build (pull_request) Successful in 49s
Python / verify (pull_request) Successful in 1m35s
Rust / fmt (pull_request) Successful in 36s
Rust / clippy (pull_request) Successful in 54s
This commit is contained in:
@@ -1,18 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "segment.hpp"
|
||||
#include "chatstore.hpp"
|
||||
#include "tool.hpp"
|
||||
#include "turn.hpp"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QJsonArray>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
class QJsonObject;
|
||||
class QNetworkReply;
|
||||
@@ -21,80 +22,75 @@ namespace ZShell::llm {
|
||||
|
||||
class ChatGeneration;
|
||||
class ChatSession;
|
||||
class LlmSegment;
|
||||
class LlmTool;
|
||||
|
||||
class LlmClient : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||
Q_PROPERTY(QString model READ model NOTIFY modelChanged)
|
||||
Q_PROPERTY(
|
||||
QStringList availableModels READ availableModels NOTIFY
|
||||
availableModelsChanged)
|
||||
Q_PROPERTY(int contextSize READ contextSize NOTIFY contextSizeChanged)
|
||||
Q_PROPERTY(
|
||||
bool toolsEnabled READ toolsEnabled WRITE setToolsEnabled NOTIFY
|
||||
toolsEnabledChanged)
|
||||
Q_PROPERTY(
|
||||
bool sandboxEnabled READ sandboxEnabled WRITE setSandboxEnabled NOTIFY
|
||||
sandboxEnabledChanged)
|
||||
Q_PROPERTY(QString serverError READ serverError NOTIFY serverErrorChanged)
|
||||
Q_PROPERTY(ZShell::llm::ChatStore* chats READ chats CONSTANT)
|
||||
|
||||
public:
|
||||
explicit LlmClient(QObject* parent = nullptr);
|
||||
~LlmClient() override;
|
||||
|
||||
[[nodiscard]] QString endpoint() const { return m_endpoint; }
|
||||
[[nodiscard]] ChatStore* chats() const { return m_store; }
|
||||
|
||||
[[nodiscard]] bool busy() const { return m_busy; }
|
||||
[[nodiscard]] QString model() const { return m_model; }
|
||||
[[nodiscard]] double temperature() const { return m_temperature; }
|
||||
[[nodiscard]] QStringList availableModels() const {
|
||||
return m_availableModels;
|
||||
}
|
||||
[[nodiscard]] int contextSize() const { return m_contextSize; }
|
||||
[[nodiscard]] ToolRegistry* tools() const { return m_tools; }
|
||||
[[nodiscard]] QString serverError() const { return m_serverError; }
|
||||
void setEndpoint(const QString& value);
|
||||
void setModel(const QString& value);
|
||||
void setTemperature(double value);
|
||||
void setContextSize(int size);
|
||||
void probeContextSize(std::function<void()> done = {});
|
||||
void refreshAllStates();
|
||||
|
||||
[[nodiscard]] bool busy() const { return m_busy; }
|
||||
[[nodiscard]] int contextSize() const { return m_tools->contextSize(); }
|
||||
[[nodiscard]] bool toolsEnabled() const { return m_tools->enabled(); }
|
||||
void setToolsEnabled(bool value) { m_tools->setEnabled(value); }
|
||||
[[nodiscard]] bool sandboxEnabled() const { return m_sandboxEnabled; }
|
||||
[[nodiscard]] bool sandboxEnabled() const {
|
||||
return m_tools->sandboxEnabled();
|
||||
}
|
||||
[[nodiscard]] QString serverError() const { return m_serverError; }
|
||||
[[nodiscard]] ChatSession* streamingSession() const {
|
||||
return m_turn ? m_turn->session() : nullptr;
|
||||
}
|
||||
|
||||
void setToolsEnabled(bool value);
|
||||
void setSandboxEnabled(bool value);
|
||||
[[nodiscard]] QString activeWorkspace() const;
|
||||
[[nodiscard]] QString streamingChatId() const { return m_streamingChatId; }
|
||||
[[nodiscard]] ChatSession* streamingSession() const { return m_active; }
|
||||
|
||||
Q_INVOKABLE void selectModel(const QString& id);
|
||||
Q_INVOKABLE void stop();
|
||||
Q_INVOKABLE void refreshModels();
|
||||
Q_INVOKABLE void refreshFromServer();
|
||||
|
||||
void startGeneration(ChatSession* session, ChatGeneration* target);
|
||||
void stop();
|
||||
void endStream();
|
||||
void clearOnFinish(ChatSession* session);
|
||||
void sessionRemoved(ChatSession* session);
|
||||
|
||||
void approveTools();
|
||||
void denyTools();
|
||||
|
||||
void refreshModels();
|
||||
void approveTools(ZShell::llm::ChatGeneration* generation);
|
||||
void denyTools(ZShell::llm::ChatGeneration* generation);
|
||||
void requestTitle(ChatSession* session, const QString& userText);
|
||||
void requestIcon(ChatSession* session, const QString& userText);
|
||||
|
||||
Q_SIGNALS:
|
||||
void busyChanged();
|
||||
void endpointChanged();
|
||||
void modelChanged();
|
||||
void availableModelsChanged();
|
||||
void contextSizeChanged();
|
||||
void toolsEnabledChanged();
|
||||
void streamingChatIdChanged();
|
||||
void errorOccurred(const QString& message);
|
||||
void sandboxEnabledChanged();
|
||||
void serverErrorChanged();
|
||||
void titleSuggested(ZShell::llm::ChatSession* session, const QString& title);
|
||||
void iconSuggested(ZShell::llm::ChatSession* session, const QString& icon);
|
||||
void generationFailed(
|
||||
ZShell::llm::ChatSession* session, const QString& message);
|
||||
|
||||
private:
|
||||
struct ToolCallBuilder {
|
||||
QString id;
|
||||
QString name;
|
||||
QString arguments;
|
||||
QPointer<LlmSegment> segment;
|
||||
bool seen = false;
|
||||
};
|
||||
|
||||
void sendRound();
|
||||
QJsonArray buildContextMessages(
|
||||
ChatSession* session, int stopBeforeRow, int extraReserveTokens) const;
|
||||
void appendSandboxPreamble(QJsonArray& messages);
|
||||
void applyToolCallDelta(const QJsonObject& call);
|
||||
void roundFinished();
|
||||
void executeAllCalls();
|
||||
@@ -102,13 +98,17 @@ class LlmClient : public QObject {
|
||||
void setApprovalPending(bool value);
|
||||
void finishPendingCalls(const QString& resultText);
|
||||
void finishTurn();
|
||||
void endStream();
|
||||
void fail(const QString& message);
|
||||
void handleLine(const QByteArray& line);
|
||||
void drainBuffer();
|
||||
void updateTokenUsage(const QJsonObject& data);
|
||||
void setBusy(bool value);
|
||||
void setStreamingChatId(const QString& id);
|
||||
void setServerError(const QString& value);
|
||||
void setModel(const QString& value);
|
||||
void setContextSize(int size);
|
||||
void probeContextSize(std::function<void()> done = {});
|
||||
void refreshAllStates();
|
||||
void shortRequest(
|
||||
const QString& tag,
|
||||
const QString& systemPrompt,
|
||||
@@ -119,42 +119,22 @@ class LlmClient : public QObject {
|
||||
static QString jsonErrorMessage(const QByteArray& body);
|
||||
static QString serverErrorMessage(
|
||||
const QByteArray& body, const QString& fallback);
|
||||
[[nodiscard]] ToolContext toolContext() const;
|
||||
|
||||
QNetworkAccessManager m_manager;
|
||||
ChatStore* m_store = nullptr;
|
||||
ToolRegistry* m_tools = nullptr;
|
||||
std::unique_ptr<Turn> m_turn;
|
||||
QNetworkReply* m_reply = nullptr;
|
||||
QByteArray m_buffer;
|
||||
QTimer m_refreshTimer;
|
||||
QPointer<ChatSession> m_active;
|
||||
QPointer<ChatGeneration> m_streaming;
|
||||
QPointer<ChatSession> m_pendingClear;
|
||||
bool m_busy = false;
|
||||
QString m_streamingChatId;
|
||||
QString m_endpoint;
|
||||
QString m_model;
|
||||
QStringList m_availableModels;
|
||||
QString m_serverError;
|
||||
double m_temperature = 0.7;
|
||||
int m_contextSize = 0;
|
||||
|
||||
QJsonArray m_transcript;
|
||||
QList<ToolCallBuilder> m_callBuilders;
|
||||
struct ToolCallResult {
|
||||
QString content;
|
||||
bool success = false;
|
||||
};
|
||||
QList<ToolCallResult> m_callResults;
|
||||
QString m_finishReason;
|
||||
int m_round = 0;
|
||||
qsizetype m_contentMark = 0;
|
||||
qsizetype m_reasoningMark = 0;
|
||||
bool m_sandboxEnabled = true;
|
||||
bool m_roundDone = false;
|
||||
bool m_streamDone = false;
|
||||
bool m_toolPhase = false;
|
||||
bool m_approvalPending = false;
|
||||
bool m_contextRetryUsed = false;
|
||||
int m_pendingCalls = 0;
|
||||
bool m_busy = false;
|
||||
bool m_configEnabled = true;
|
||||
static constexpr int kMaxToolRounds = 12;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user