mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-07-01 09:41:59 +00:00
Implement error handling for tool calls.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
parent
5fc2ff8e69
commit
244b82622c
@ -29,7 +29,14 @@ QString BraveSearch::run(const QJsonObject ¶meters, qint64 timeout)
|
|||||||
worker.request(apiKey, query, count);
|
worker.request(apiKey, query, count);
|
||||||
});
|
});
|
||||||
workerThread.start();
|
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.quit();
|
||||||
workerThread.wait();
|
workerThread.wait();
|
||||||
return worker.response();
|
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);
|
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
|
// This parses the response from brave and formats it in json that conforms to the de facto
|
||||||
// standard in SourceExcerpts::fromJson(...)
|
// standard in SourceExcerpts::fromJson(...)
|
||||||
QJsonParseError err;
|
QJsonParseError err;
|
||||||
QJsonDocument document = QJsonDocument::fromJson(jsonResponse, &err);
|
QJsonDocument document = QJsonDocument::fromJson(jsonResponse, &err);
|
||||||
if (err.error != QJsonParseError::NoError) {
|
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();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +155,6 @@ void BraveAPIWorker::handleFinished()
|
|||||||
m_response = cleanBraveResponse(jsonData);
|
m_response = cleanBraveResponse(jsonData);
|
||||||
} else {
|
} else {
|
||||||
QByteArray jsonData = jsonReply->readAll();
|
QByteArray jsonData = jsonReply->readAll();
|
||||||
qWarning() << "ERROR: Could not search brave" << jsonReply->error() << jsonReply->errorString() << jsonData;
|
|
||||||
jsonReply->deleteLater();
|
jsonReply->deleteLater();
|
||||||
}
|
}
|
||||||
emit finished();
|
emit finished();
|
||||||
@ -157,7 +164,7 @@ void BraveAPIWorker::handleErrorOccurred(QNetworkReply::NetworkError code)
|
|||||||
{
|
{
|
||||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||||
Q_ASSERT(reply);
|
Q_ASSERT(reply);
|
||||||
qWarning().noquote() << "ERROR: BraveAPIWorker::handleErrorOccurred got HTTP Error" << code << "response:"
|
m_error = ToolEnums::Error::UnknownError;
|
||||||
<< reply->errorString();
|
m_errorString = QString(tr("ERROR: brave search code: %1 response: %2")).arg(code).arg(reply->errorString());
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ public:
|
|||||||
virtual ~BraveAPIWorker() {}
|
virtual ~BraveAPIWorker() {}
|
||||||
|
|
||||||
QString response() const { return m_response; }
|
QString response() const { return m_response; }
|
||||||
|
ToolEnums::Error error() const { return m_error; }
|
||||||
|
QString errorString() const { return m_errorString; }
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void request(const QString &apiKey, const QString &query, int count);
|
void request(const QString &apiKey, const QString &query, int count);
|
||||||
@ -25,21 +27,30 @@ Q_SIGNALS:
|
|||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
QString cleanBraveResponse(const QByteArray& jsonResponse);
|
||||||
void handleFinished();
|
void handleFinished();
|
||||||
void handleErrorOccurred(QNetworkReply::NetworkError code);
|
void handleErrorOccurred(QNetworkReply::NetworkError code);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager *m_networkManager;
|
QNetworkAccessManager *m_networkManager;
|
||||||
QString m_response;
|
QString m_response;
|
||||||
|
ToolEnums::Error m_error;
|
||||||
|
QString m_errorString;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BraveSearch : public Tool {
|
class BraveSearch : public Tool {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
BraveSearch() : Tool() {}
|
BraveSearch() : Tool(), m_error(ToolEnums::Error::NoError) {}
|
||||||
virtual ~BraveSearch() {}
|
virtual ~BraveSearch() {}
|
||||||
|
|
||||||
QString run(const QJsonObject ¶meters, qint64 timeout = 2000) override;
|
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
|
#endif // BRAVESEARCH_H
|
||||||
|
@ -871,6 +871,7 @@ bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString
|
|||||||
// FIXME: In the future this will try to match the tool call to a list of tools that are supported
|
// 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
|
// according to MySettings, but for now only brave search is supported
|
||||||
if (tool != "brave_search" || !args.contains("query")) {
|
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;
|
qWarning() << "ERROR: Could not find the tool and correct parameters for " << toolCall;
|
||||||
return handleFailedToolCall(trimmed, elapsed);
|
return handleFailedToolCall(trimmed, elapsed);
|
||||||
}
|
}
|
||||||
@ -887,7 +888,7 @@ bool ChatLLM::promptInternal(const QList<QString> &collectionList, const QString
|
|||||||
parameters.insert("query", query);
|
parameters.insert("query", query);
|
||||||
parameters.insert("count", 2);
|
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*/);
|
const QString braveResponse = brave.run(parameters, 2000 /*msecs to timeout*/);
|
||||||
|
|
||||||
QString parseError;
|
QString parseError;
|
||||||
|
@ -27,6 +27,12 @@ QString LocalDocsSearch::run(const QJsonObject ¶meters, qint64 timeout)
|
|||||||
worker.request(collections, text, count);
|
worker.request(collections, text, count);
|
||||||
});
|
});
|
||||||
workerThread.start();
|
workerThread.start();
|
||||||
|
bool timedOut = !workerThread.wait(timeout);
|
||||||
|
if (timedOut) {
|
||||||
|
m_error = ToolEnums::Error::TimeoutError;
|
||||||
|
m_errorString = tr("ERROR: localdocs timeout");
|
||||||
|
}
|
||||||
|
|
||||||
workerThread.wait(timeout);
|
workerThread.wait(timeout);
|
||||||
workerThread.quit();
|
workerThread.quit();
|
||||||
workerThread.wait();
|
workerThread.wait();
|
||||||
|
@ -27,10 +27,16 @@ private:
|
|||||||
class LocalDocsSearch : public Tool {
|
class LocalDocsSearch : public Tool {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
LocalDocsSearch() : Tool() {}
|
LocalDocsSearch() : Tool(), m_error(ToolEnums::Error::NoError) {}
|
||||||
virtual ~LocalDocsSearch() {}
|
virtual ~LocalDocsSearch() {}
|
||||||
|
|
||||||
QString run(const QJsonObject ¶meters, qint64 timeout = 2000) override;
|
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
|
#endif // LOCALDOCSSEARCH_H
|
||||||
|
@ -9,15 +9,20 @@ using namespace Qt::Literals::StringLiterals;
|
|||||||
namespace ToolEnums {
|
namespace ToolEnums {
|
||||||
Q_NAMESPACE
|
Q_NAMESPACE
|
||||||
enum class ConnectionType {
|
enum class ConnectionType {
|
||||||
Builtin = 0, // A built-in tool with bespoke connection type
|
BuiltinConnection = 0, // A built-in tool with bespoke connection type
|
||||||
Local = 1, // Starts a local process and communicates via stdin/stdout/stderr
|
LocalConnection = 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
|
LocalServerConnection = 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
|
RemoteConnection = 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
|
RemoteServerConnection = 4 // Connects to an existing remote process and communicates via some networking protocol TBD
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(ConnectionType)
|
Q_ENUM_NS(ConnectionType)
|
||||||
|
|
||||||
|
enum class Error {
|
||||||
|
NoError = 0,
|
||||||
|
TimeoutError = 2,
|
||||||
|
UnknownError = 499,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
using namespace ToolEnums;
|
|
||||||
|
|
||||||
struct ToolInfo {
|
struct ToolInfo {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
@ -25,14 +30,14 @@ struct ToolInfo {
|
|||||||
Q_PROPERTY(QString description MEMBER description)
|
Q_PROPERTY(QString description MEMBER description)
|
||||||
Q_PROPERTY(QJsonObject parameters MEMBER parameters)
|
Q_PROPERTY(QJsonObject parameters MEMBER parameters)
|
||||||
Q_PROPERTY(bool isEnabled MEMBER isEnabled)
|
Q_PROPERTY(bool isEnabled MEMBER isEnabled)
|
||||||
Q_PROPERTY(ConnectionType connectionType MEMBER connectionType)
|
Q_PROPERTY(ToolEnums::ConnectionType connectionType MEMBER connectionType)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QString name;
|
QString name;
|
||||||
QString description;
|
QString description;
|
||||||
QJsonObject parameters;
|
QJsonObject parameters;
|
||||||
bool isEnabled;
|
bool isEnabled;
|
||||||
ConnectionType connectionType;
|
ToolEnums::ConnectionType connectionType;
|
||||||
|
|
||||||
// FIXME: Should we go with essentially the OpenAI/ollama consensus for these tool
|
// 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:
|
// 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) {}
|
Tool() : QObject(nullptr) {}
|
||||||
virtual ~Tool() {}
|
virtual ~Tool() {}
|
||||||
|
|
||||||
// FIXME: How to handle errors?
|
|
||||||
virtual QString run(const QJsonObject ¶meters, qint64 timeout = 2000) = 0;
|
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
|
#endif // TOOL_H
|
||||||
|
Loading…
Reference in New Issue
Block a user