mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-06-30 09:13:40 +00:00
Tool model.
Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
parent
244b82622c
commit
cedba6cd10
@ -124,7 +124,7 @@ qt_add_executable(chat
|
|||||||
sourceexcerpt.h sourceexcerpt.cpp
|
sourceexcerpt.h sourceexcerpt.cpp
|
||||||
server.h server.cpp
|
server.h server.cpp
|
||||||
logger.h logger.cpp
|
logger.h logger.cpp
|
||||||
tool.h tool.cpp
|
tool.h tool.cpp toolmodel.h toolmodel.cpp
|
||||||
${APP_ICON_RESOURCE}
|
${APP_ICON_RESOURCE}
|
||||||
${CHAT_EXE_RESOURCES}
|
${CHAT_EXE_RESOURCES}
|
||||||
)
|
)
|
||||||
|
@ -31,7 +31,7 @@ ChatListModel *ChatListModel::globalInstance()
|
|||||||
ChatListModel::ChatListModel()
|
ChatListModel::ChatListModel()
|
||||||
: QAbstractListModel(nullptr) {
|
: QAbstractListModel(nullptr) {
|
||||||
|
|
||||||
QCoreApplication::instance()->installEventFilter(this);
|
QCoreApplication::instance()->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatListModel::eventFilter(QObject *obj, QEvent *ev)
|
bool ChatListModel::eventFilter(QObject *obj, QEvent *ev)
|
||||||
|
@ -67,5 +67,5 @@ MySettingsTab {
|
|||||||
height: 1
|
height: 1
|
||||||
color: theme.settingsDivider
|
color: theme.settingsDivider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,63 +8,26 @@ using namespace Qt::Literals::StringLiterals;
|
|||||||
|
|
||||||
namespace ToolEnums {
|
namespace ToolEnums {
|
||||||
Q_NAMESPACE
|
Q_NAMESPACE
|
||||||
enum class ConnectionType {
|
|
||||||
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 {
|
enum class Error {
|
||||||
NoError = 0,
|
NoError = 0,
|
||||||
TimeoutError = 2,
|
TimeoutError = 2,
|
||||||
UnknownError = 499,
|
UnknownError = 499,
|
||||||
};
|
};
|
||||||
|
Q_ENUM_NS(Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ToolInfo {
|
|
||||||
Q_GADGET
|
|
||||||
Q_PROPERTY(QString name MEMBER name)
|
|
||||||
Q_PROPERTY(QString description MEMBER description)
|
|
||||||
Q_PROPERTY(QJsonObject parameters MEMBER parameters)
|
|
||||||
Q_PROPERTY(bool isEnabled MEMBER isEnabled)
|
|
||||||
Q_PROPERTY(ToolEnums::ConnectionType connectionType MEMBER connectionType)
|
|
||||||
|
|
||||||
public:
|
|
||||||
QString name;
|
|
||||||
QString description;
|
|
||||||
QJsonObject parameters;
|
|
||||||
bool isEnabled;
|
|
||||||
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:
|
|
||||||
// https://platform.openai.com/docs/api-reference/runs/createRun#runs-createrun-tools
|
|
||||||
// https://github.com/ollama/ollama/blob/main/docs/api.md#chat-request-with-tools
|
|
||||||
QJsonObject toJson() const
|
|
||||||
{
|
|
||||||
QJsonObject result;
|
|
||||||
result.insert("name", name);
|
|
||||||
result.insert("description", description);
|
|
||||||
result.insert("parameters", parameters);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ToolInfo fromJson(const QString &json);
|
|
||||||
|
|
||||||
bool operator==(const ToolInfo &other) const {
|
|
||||||
return name == other.name;
|
|
||||||
}
|
|
||||||
bool operator!=(const ToolInfo &other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Q_DECLARE_METATYPE(ToolInfo)
|
|
||||||
|
|
||||||
class Tool : public QObject {
|
class Tool : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString name MEMBER name)
|
||||||
|
Q_PROPERTY(QString description MEMBER description)
|
||||||
|
Q_PROPERTY(QString function MEMBER function)
|
||||||
|
Q_PROPERTY(QJsonObject paramSchema MEMBER paramSchema)
|
||||||
|
Q_PROPERTY(QUrl url MEMBER url)
|
||||||
|
Q_PROPERTY(bool isEnabled MEMBER isEnabled)
|
||||||
|
Q_PROPERTY(bool isBuiltin MEMBER isBuiltin)
|
||||||
|
Q_PROPERTY(bool forceUsage MEMBER forceUsage)
|
||||||
|
Q_PROPERTY(bool excerpts MEMBER excerpts)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Tool() : QObject(nullptr) {}
|
Tool() : QObject(nullptr) {}
|
||||||
virtual ~Tool() {}
|
virtual ~Tool() {}
|
||||||
@ -72,6 +35,29 @@ public:
|
|||||||
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 ToolEnums::Error error() const { return ToolEnums::Error::NoError; }
|
||||||
virtual QString errorString() const { return QString(); }
|
virtual QString errorString() const { return QString(); }
|
||||||
|
|
||||||
|
QString name; // [Required] Human readable name of the tool.
|
||||||
|
QString description; // [Required] Human readable description of the tool.
|
||||||
|
QString function; // [Required] Must be unique. Name of the function to invoke. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
|
||||||
|
QJsonObject paramSchema; // [Optional] Json schema describing the tool's parameters. An empty object specifies no parameters.
|
||||||
|
// https://json-schema.org/understanding-json-schema/
|
||||||
|
QUrl url; // [Optional] The local file or remote resource use to invoke the tool.
|
||||||
|
bool isEnabled = false; // [Optional] Whether the tool is currently enabled
|
||||||
|
bool isBuiltin = false; // [Optional] Whether the tool is built-in
|
||||||
|
bool forceUsage = false; // [Optional] Whether we should attempt to force usage of the tool rather than let the LLM decide. NOTE: Not always possible.
|
||||||
|
bool excerpts = false; // [Optional] Whether json result produces source excerpts.
|
||||||
|
|
||||||
|
// 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:
|
||||||
|
// https://platform.openai.com/docs/api-reference/runs/createRun#runs-createrun-tools
|
||||||
|
// https://github.com/ollama/ollama/blob/main/docs/api.md#chat-request-with-tools
|
||||||
|
|
||||||
|
bool operator==(const Tool &other) const {
|
||||||
|
return function == other.function;
|
||||||
|
}
|
||||||
|
bool operator!=(const Tool &other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TOOL_H
|
#endif // TOOL_H
|
||||||
|
103
gpt4all-chat/toolmodel.cpp
Normal file
103
gpt4all-chat/toolmodel.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "toolmodel.h"
|
||||||
|
|
||||||
|
#include <QGlobalStatic>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
#include "bravesearch.h"
|
||||||
|
#include "localdocssearch.h"
|
||||||
|
|
||||||
|
class MyToolModel: public ToolModel { };
|
||||||
|
Q_GLOBAL_STATIC(MyToolModel, toolModelInstance)
|
||||||
|
ToolModel *ToolModel::globalInstance()
|
||||||
|
{
|
||||||
|
return toolModelInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolModel::ToolModel()
|
||||||
|
: QAbstractListModel(nullptr) {
|
||||||
|
|
||||||
|
QCoreApplication::instance()->installEventFilter(this);
|
||||||
|
|
||||||
|
Tool* localDocsSearch = new LocalDocsSearch;
|
||||||
|
localDocsSearch->name = tr("LocalDocs search");
|
||||||
|
localDocsSearch->description = tr("Search the local docs");
|
||||||
|
localDocsSearch->function = "localdocs_search";
|
||||||
|
localDocsSearch->isBuiltin = true;
|
||||||
|
localDocsSearch->excerpts = true;
|
||||||
|
localDocsSearch->forceUsage = true; // FIXME: persistent setting
|
||||||
|
localDocsSearch->isEnabled = true; // FIXME: persistent setting
|
||||||
|
|
||||||
|
QString localParamSchema = R"({
|
||||||
|
"collections": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "The collections to search",
|
||||||
|
"required": true,
|
||||||
|
"modelGenerated": false,
|
||||||
|
"userConfigured": false
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The query to search",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "The number of excerpts to return",
|
||||||
|
"required": true,
|
||||||
|
"modelGenerated": false
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
|
||||||
|
QJsonDocument localJsonDoc = QJsonDocument::fromJson(localParamSchema.toUtf8());
|
||||||
|
Q_ASSERT(!localJsonDoc.isNull() && localJsonDoc.isObject());
|
||||||
|
localDocsSearch->paramSchema = localJsonDoc.object();
|
||||||
|
m_tools.append(localDocsSearch);
|
||||||
|
m_toolMap.insert(localDocsSearch->function, localDocsSearch);
|
||||||
|
|
||||||
|
Tool *braveSearch = new BraveSearch;
|
||||||
|
braveSearch->name = tr("Brave web search");
|
||||||
|
braveSearch->description = tr("Search the web using brave.com");
|
||||||
|
braveSearch->function = "brave_search";
|
||||||
|
braveSearch->isBuiltin = true;
|
||||||
|
braveSearch->excerpts = true;
|
||||||
|
braveSearch->forceUsage = false; // FIXME: persistent setting
|
||||||
|
braveSearch->isEnabled = false; // FIXME: persistent setting
|
||||||
|
|
||||||
|
QString braveParamSchema = R"({
|
||||||
|
"apiKey": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The api key to use",
|
||||||
|
"required": true,
|
||||||
|
"modelGenerated": false,
|
||||||
|
"userConfigured": true
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The query to search",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "The number of excerpts to return",
|
||||||
|
"required": true,
|
||||||
|
"modelGenerated": false
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
|
||||||
|
QJsonDocument braveJsonDoc = QJsonDocument::fromJson(braveParamSchema.toUtf8());
|
||||||
|
Q_ASSERT(!braveJsonDoc.isNull() && braveJsonDoc.isObject());
|
||||||
|
braveSearch->paramSchema = braveJsonDoc.object();
|
||||||
|
m_tools.append(braveSearch);
|
||||||
|
m_toolMap.insert(braveSearch->function, braveSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToolModel::eventFilter(QObject *obj, QEvent *ev)
|
||||||
|
{
|
||||||
|
if (obj == QCoreApplication::instance() && ev->type() == QEvent::LanguageChange)
|
||||||
|
emit dataChanged(index(0, 0), index(m_tools.size() - 1, 0));
|
||||||
|
return false;
|
||||||
|
}
|
112
gpt4all-chat/toolmodel.h
Normal file
112
gpt4all-chat/toolmodel.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#ifndef TOOLMODEL_H
|
||||||
|
#define TOOLMODEL_H
|
||||||
|
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
class ToolModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ToolModel *globalInstance();
|
||||||
|
|
||||||
|
enum Roles {
|
||||||
|
NameRole = Qt::UserRole + 1,
|
||||||
|
DescriptionRole,
|
||||||
|
FunctionRole,
|
||||||
|
ParametersRole,
|
||||||
|
UrlRole,
|
||||||
|
ApiKeyRole,
|
||||||
|
KeyRequiredRole,
|
||||||
|
IsEnabledRole,
|
||||||
|
IsBuiltinRole,
|
||||||
|
ForceUsageRole,
|
||||||
|
ExcerptsRole,
|
||||||
|
};
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return m_tools.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
|
||||||
|
{
|
||||||
|
if (!index.isValid() || index.row() < 0 || index.row() >= m_tools.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
const Tool *item = m_tools.at(index.row());
|
||||||
|
switch (role) {
|
||||||
|
case NameRole:
|
||||||
|
return item->name;
|
||||||
|
case DescriptionRole:
|
||||||
|
return item->description;
|
||||||
|
case FunctionRole:
|
||||||
|
return item->function;
|
||||||
|
case ParametersRole:
|
||||||
|
return item->paramSchema;
|
||||||
|
case UrlRole:
|
||||||
|
return item->url;
|
||||||
|
case IsEnabledRole:
|
||||||
|
return item->isEnabled;
|
||||||
|
case IsBuiltinRole:
|
||||||
|
return item->isBuiltin;
|
||||||
|
case ForceUsageRole:
|
||||||
|
return item->forceUsage;
|
||||||
|
case ExcerptsRole:
|
||||||
|
return item->excerpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> roles;
|
||||||
|
roles[NameRole] = "name";
|
||||||
|
roles[DescriptionRole] = "description";
|
||||||
|
roles[FunctionRole] = "function";
|
||||||
|
roles[ParametersRole] = "parameters";
|
||||||
|
roles[UrlRole] = "url";
|
||||||
|
roles[ApiKeyRole] = "apiKey";
|
||||||
|
roles[KeyRequiredRole] = "keyRequired";
|
||||||
|
roles[IsEnabledRole] = "isEnabled";
|
||||||
|
roles[IsBuiltinRole] = "isBuiltin";
|
||||||
|
roles[ForceUsageRole] = "forceUsage";
|
||||||
|
roles[ExcerptsRole] = "excerpts";
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE Tool* get(int index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= m_tools.size()) return nullptr;
|
||||||
|
return m_tools.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE Tool *get(const QString &id) const
|
||||||
|
{
|
||||||
|
if (!m_toolMap.contains(id)) return nullptr;
|
||||||
|
return m_toolMap.value(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int count() const { return m_tools.size(); }
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void countChanged();
|
||||||
|
void valueChanged(int index, const QString &value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit ToolModel();
|
||||||
|
~ToolModel() {}
|
||||||
|
friend class MyToolModel;
|
||||||
|
QList<Tool*> m_tools;
|
||||||
|
QHash<QString, Tool*> m_toolMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TOOLMODEL_H
|
Loading…
Reference in New Issue
Block a user