mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-06-30 01:02:35 +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
|
||||
server.h server.cpp
|
||||
logger.h logger.cpp
|
||||
tool.h tool.cpp
|
||||
tool.h tool.cpp toolmodel.h toolmodel.cpp
|
||||
${APP_ICON_RESOURCE}
|
||||
${CHAT_EXE_RESOURCES}
|
||||
)
|
||||
|
@ -31,7 +31,7 @@ ChatListModel *ChatListModel::globalInstance()
|
||||
ChatListModel::ChatListModel()
|
||||
: QAbstractListModel(nullptr) {
|
||||
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool ChatListModel::eventFilter(QObject *obj, QEvent *ev)
|
||||
|
@ -67,5 +67,5 @@ MySettingsTab {
|
||||
height: 1
|
||||
color: theme.settingsDivider
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,63 +8,26 @@ using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
namespace ToolEnums {
|
||||
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 {
|
||||
NoError = 0,
|
||||
TimeoutError = 2,
|
||||
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 {
|
||||
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:
|
||||
Tool() : QObject(nullptr) {}
|
||||
virtual ~Tool() {}
|
||||
@ -72,6 +35,29 @@ public:
|
||||
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(); }
|
||||
|
||||
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
|
||||
|
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