diff --git a/gpt4all-chat/bravesearch.cpp b/gpt4all-chat/bravesearch.cpp index e691810b..a9c950b0 100644 --- a/gpt4all-chat/bravesearch.cpp +++ b/gpt4all-chat/bravesearch.cpp @@ -29,7 +29,14 @@ QString BraveSearch::run(const QJsonObject ¶meters, qint64 timeout) worker.request(apiKey, query, count); }); workerThread.start(); - workerThread.wait(timeout); + bool timedOut = !workerThread.wait(timeout); + if (timedOut) { + m_error = ToolEnums::Error::TimeoutError; + m_errorString = tr("ERROR: brave search timeout"); + } else { + m_error = worker.error(); + m_errorString = worker.errorString(); + } workerThread.quit(); workerThread.wait(); return worker.response(); @@ -62,14 +69,15 @@ void BraveAPIWorker::request(const QString &apiKey, const QString &query, int co connect(reply, &QNetworkReply::errorOccurred, this, &BraveAPIWorker::handleErrorOccurred); } -static QString cleanBraveResponse(const QByteArray& jsonResponse) +QString BraveAPIWorker::cleanBraveResponse(const QByteArray& jsonResponse) { // This parses the response from brave and formats it in json that conforms to the de facto // standard in SourceExcerpts::fromJson(...) QJsonParseError err; QJsonDocument document = QJsonDocument::fromJson(jsonResponse, &err); if (err.error != QJsonParseError::NoError) { - qWarning() << "ERROR: Couldn't parse brave response: " << jsonResponse << err.errorString(); + m_error = ToolEnums::Error::UnknownError; + m_errorString = QString(tr("ERROR: brave search could not parse json response: %1")).arg(jsonResponse); return QString(); } @@ -147,7 +155,6 @@ void BraveAPIWorker::handleFinished() m_response = cleanBraveResponse(jsonData); } else { QByteArray jsonData = jsonReply->readAll(); - qWarning() << "ERROR: Could not search brave" << jsonReply->error() << jsonReply->errorString() << jsonData; jsonReply->deleteLater(); } emit finished(); @@ -157,7 +164,7 @@ void BraveAPIWorker::handleErrorOccurred(QNetworkReply::NetworkError code) { QNetworkReply *reply = qobject_cast(sender()); Q_ASSERT(reply); - qWarning().noquote() << "ERROR: BraveAPIWorker::handleErrorOccurred got HTTP Error" << code << "response:" - << reply->errorString(); + m_error = ToolEnums::Error::UnknownError; + m_errorString = QString(tr("ERROR: brave search code: %1 response: %2")).arg(code).arg(reply->errorString()); emit finished(); } diff --git a/gpt4all-chat/bravesearch.h b/gpt4all-chat/bravesearch.h index 28f84b15..dc0cc042 100644 --- a/gpt4all-chat/bravesearch.h +++ b/gpt4all-chat/bravesearch.h @@ -17,6 +17,8 @@ public: virtual ~BraveAPIWorker() {} QString response() const { return m_response; } + ToolEnums::Error error() const { return m_error; } + QString errorString() const { return m_errorString; } public Q_SLOTS: void request(const QString &apiKey, const QString &query, int count); @@ -25,21 +27,30 @@ Q_SIGNALS: void finished(); private Q_SLOTS: + QString cleanBraveResponse(const QByteArray& jsonResponse); void handleFinished(); void handleErrorOccurred(QNetworkReply::NetworkError code); private: QNetworkAccessManager *m_networkManager; QString m_response; + ToolEnums::Error m_error; + QString m_errorString; }; class BraveSearch : public Tool { Q_OBJECT public: - BraveSearch() : Tool() {} + BraveSearch() : Tool(), m_error(ToolEnums::Error::NoError) {} virtual ~BraveSearch() {} QString run(const QJsonObject ¶meters, qint64 timeout = 2000) override; + ToolEnums::Error error() const override { return m_error; } + QString errorString() const override { return m_errorString; } + +private: + ToolEnums::Error m_error; + QString m_errorString; }; #endif // BRAVESEARCH_H diff --git a/gpt4all-chat/chatllm.cpp b/gpt4all-chat/chatllm.cpp index bea454ee..38151496 100644 --- a/gpt4all-chat/chatllm.cpp +++ b/gpt4all-chat/chatllm.cpp @@ -871,6 +871,7 @@ bool ChatLLM::promptInternal(const QList &collectionList, const QString // FIXME: In the future this will try to match the tool call to a list of tools that are supported // according to MySettings, but for now only brave search is supported if (tool != "brave_search" || !args.contains("query")) { + // FIXME: Need to surface errors to the UI qWarning() << "ERROR: Could not find the tool and correct parameters for " << toolCall; return handleFailedToolCall(trimmed, elapsed); } @@ -887,7 +888,7 @@ bool ChatLLM::promptInternal(const QList &collectionList, const QString parameters.insert("query", query); parameters.insert("count", 2); - // FIXME: This has to handle errors of the tool call + // FIXME: Need to surface errors to the UI const QString braveResponse = brave.run(parameters, 2000 /*msecs to timeout*/); QString parseError; diff --git a/gpt4all-chat/localdocssearch.cpp b/gpt4all-chat/localdocssearch.cpp index 77becf4e..2fc9dbe2 100644 --- a/gpt4all-chat/localdocssearch.cpp +++ b/gpt4all-chat/localdocssearch.cpp @@ -27,6 +27,12 @@ QString LocalDocsSearch::run(const QJsonObject ¶meters, qint64 timeout) worker.request(collections, text, count); }); workerThread.start(); + bool timedOut = !workerThread.wait(timeout); + if (timedOut) { + m_error = ToolEnums::Error::TimeoutError; + m_errorString = tr("ERROR: localdocs timeout"); + } + workerThread.wait(timeout); workerThread.quit(); workerThread.wait(); diff --git a/gpt4all-chat/localdocssearch.h b/gpt4all-chat/localdocssearch.h index 4f757a52..61e56b73 100644 --- a/gpt4all-chat/localdocssearch.h +++ b/gpt4all-chat/localdocssearch.h @@ -27,10 +27,16 @@ private: class LocalDocsSearch : public Tool { Q_OBJECT public: - LocalDocsSearch() : Tool() {} + LocalDocsSearch() : Tool(), m_error(ToolEnums::Error::NoError) {} virtual ~LocalDocsSearch() {} QString run(const QJsonObject ¶meters, qint64 timeout = 2000) override; + ToolEnums::Error error() const override { return m_error; } + QString errorString() const override { return m_errorString; } + +private: + ToolEnums::Error m_error; + QString m_errorString; }; #endif // LOCALDOCSSEARCH_H diff --git a/gpt4all-chat/tool.h b/gpt4all-chat/tool.h index 3dac88e7..aa8ea3b2 100644 --- a/gpt4all-chat/tool.h +++ b/gpt4all-chat/tool.h @@ -9,15 +9,20 @@ using namespace Qt::Literals::StringLiterals; namespace ToolEnums { Q_NAMESPACE enum class ConnectionType { - Builtin = 0, // A built-in tool with bespoke connection type - Local = 1, // Starts a local process and communicates via stdin/stdout/stderr - LocalServer = 2, // Connects to an existing local process and communicates via stdin/stdout/stderr - Remote = 3, // Starts a remote process and communicates via some networking protocol TBD - RemoteServer = 4 // Connects to an existing remote process and communicates via some networking protocol TBD + BuiltinConnection = 0, // A built-in tool with bespoke connection type + LocalConnection = 1, // Starts a local process and communicates via stdin/stdout/stderr + LocalServerConnection = 2, // Connects to an existing local process and communicates via stdin/stdout/stderr + RemoteConnection = 3, // Starts a remote process and communicates via some networking protocol TBD + RemoteServerConnection = 4 // Connects to an existing remote process and communicates via some networking protocol TBD }; Q_ENUM_NS(ConnectionType) + + enum class Error { + NoError = 0, + TimeoutError = 2, + UnknownError = 499, + }; } -using namespace ToolEnums; struct ToolInfo { Q_GADGET @@ -25,14 +30,14 @@ struct ToolInfo { Q_PROPERTY(QString description MEMBER description) Q_PROPERTY(QJsonObject parameters MEMBER parameters) Q_PROPERTY(bool isEnabled MEMBER isEnabled) - Q_PROPERTY(ConnectionType connectionType MEMBER connectionType) + Q_PROPERTY(ToolEnums::ConnectionType connectionType MEMBER connectionType) public: QString name; QString description; QJsonObject parameters; bool isEnabled; - ConnectionType connectionType; + ToolEnums::ConnectionType connectionType; // FIXME: Should we go with essentially the OpenAI/ollama consensus for these tool // info files? If you install a tool in GPT4All should it need to meet the spec for these: @@ -64,8 +69,9 @@ public: Tool() : QObject(nullptr) {} virtual ~Tool() {} - // FIXME: How to handle errors? virtual QString run(const QJsonObject ¶meters, qint64 timeout = 2000) = 0; + virtual ToolEnums::Error error() const { return ToolEnums::Error::NoError; } + virtual QString errorString() const { return QString(); } }; #endif // TOOL_H