Skip to content

Commit 5859f94

Browse files
committed
Add "Tools" settings page
Where you can select which tools should be used by the assistant. Also the "Enable Tools" state from the chat input is reflected in the Chat settings page.
1 parent d24f1da commit 5859f94

7 files changed

Lines changed: 355 additions & 15 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ add_qtc_plugin(LlamaCpp
9797
tools/run_project_tool.cpp tools/run_project_tool.h
9898
tools/open_project_tool.cpp tools/open_project_tool.h
9999
tools/tool.cpp tools/tool.h
100+
toolsettingswidget.cpp toolsettingswidget.h
100101
)
101102

102103
add_subdirectory(tests)

llamachatinput.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <utils/fsengine/fileiconprovider.h>
1616

1717
#include "llamachatinput.h"
18+
#include "llamasettings.h"
1819
#include "llamatheme.h"
1920
#include "llamatr.h"
2021

@@ -83,8 +84,15 @@ void ChatInput::buildUI()
8384
m_toolsButton = new QToolButton(this);
8485
m_toolsButton->setText("O");
8586
m_toolsButton->setCheckable(true);
86-
m_toolsButton->setToolTip(Tr::tr("Enable Tools usage"));
87+
const bool toolsInitiallyEnabled = settings().toolsEnabled();
88+
m_toolsButton->setChecked(toolsInitiallyEnabled);
89+
m_toolsButton->setToolTip(toolsInitiallyEnabled
90+
? Tr::tr("Disable Tools usage")
91+
: Tr::tr("Enable Tools usage"));
8792
connect(m_toolsButton, &QToolButton::clicked, this, [this](bool checked) {
93+
settings().toolsEnabled.setValue(checked);
94+
settings().writeSettings();
95+
8896
m_toolsButton->setToolTip(checked ? Tr::tr("Disable Tools usage")
8997
: Tr::tr("Enable Tools usage"));
9098
emit toolsSupportEnabled(checked);

llamachatmanager.cpp

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,41 @@ static void addCommonPayloadParams(QJsonObject &payload)
5151

5252
static void addToolsToPayload(QJsonObject &payload)
5353
{
54-
if (settings().tools.value().isEmpty())
55-
return;
54+
const QStringList enabledTools = settings().enabledToolsList();
55+
56+
const QStringList creatorsList = ToolFactory::instance().creatorsList();
57+
QStringList toolDefinitions;
58+
for (const QString &toolName : creatorsList) {
59+
std::unique_ptr<Tool> tool = ToolFactory::instance().create(toolName);
60+
toolDefinitions << tool->toolDefinition();
61+
}
5662

5763
QJsonArray toolsArr;
58-
for (const QString &toolStr : settings().tools.value()) {
64+
for (const QString &toolStr : std::as_const(toolDefinitions)) {
5965
QJsonParseError err;
6066
QJsonDocument doc = QJsonDocument::fromJson(toolStr.toUtf8(), &err);
6167
if (err.error != QJsonParseError::NoError || !doc.isObject()) {
6268
qWarning() << "Invalid tool JSON:" << err.errorString();
6369
continue;
6470
}
65-
toolsArr.append(doc.object());
71+
72+
// Extract the tool name so we can check whether it is enabled.
73+
const QJsonObject root = doc.object();
74+
const QJsonObject functionObj = root.value(QStringLiteral("function")).toObject();
75+
const QString toolName = functionObj.value(QStringLiteral("name")).toString();
76+
77+
if (!enabledTools.contains(toolName)) {
78+
// Skip disabled tools – they must never be advertised to the server.
79+
qCInfo(llamaChatTools).nospace()
80+
<< "Tool '" << toolName << "' is disabled, not adding it to payload.";
81+
continue;
82+
}
83+
84+
toolsArr.append(root);
6685
}
6786

68-
payload["tools"] = toolsArr;
87+
if (!toolsArr.isEmpty())
88+
payload["tools"] = toolsArr;
6989
}
7090

7191
ChatManager &ChatManager::instance()
@@ -774,6 +794,30 @@ void ChatManager::executeToolAndSendResult(const QString &convId,
774794
const ToolCall &tool,
775795
std::function<void(qint64)> onChunk)
776796
{
797+
// Check whether the requested tool is enabled.
798+
if (!settings().enabledToolsList().contains(tool.name)) {
799+
qCWarning(llamaChatTools) << "Tool" << tool.name
800+
<< "was called but is disabled – skipping.";
801+
802+
// Insert a synthetic “failed” tool‑result so the conversation can continue.
803+
Message toolMsg = createToolMessage(assistantMsg);
804+
QJsonObject toolJsonMsg;
805+
toolJsonMsg["role"] = "tool";
806+
toolJsonMsg["tool_call_id"] = tool.id;
807+
toolJsonMsg["name"] = tool.name;
808+
toolJsonMsg["content"] = QStringLiteral("Tool disabled");
809+
QVariantMap toolResultExtra;
810+
toolResultExtra["tool_result"] = toolJsonMsg;
811+
toolResultExtra["tool_status"] = QStringLiteral("failed");
812+
toolMsg.extra << toolResultExtra;
813+
m_storage->appendMsg(toolMsg, assistantMsg.id);
814+
onChunk(toolMsg.id);
815+
816+
// Continue the conversation as if the tool had returned an error.
817+
generateMessage(convId, toolMsg.id, onChunk);
818+
return;
819+
}
820+
777821
QJsonParseError err;
778822
QJsonDocument doc = QJsonDocument::fromJson(tool.arguments.toUtf8(), &err);
779823
if (err.error != QJsonParseError::NoError) {

llamasettings.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "llamatr.h"
44
#include "tools/factory.h"
55
#include "tools/tool.h"
6+
#include "toolsettingswidget.h"
67

78
#include <coreplugin/dialogs/ioptionspage.h>
89
#include <projectexplorer/project.h>
@@ -14,6 +15,17 @@ using namespace Utils;
1415

1516
namespace LlamaCpp {
1617

18+
ToolsSettingsPage::ToolsSettingsPage()
19+
{
20+
setId("LlamaCpp.Tools"); // unique identifier
21+
setDisplayName(Tr::tr("Tools")); // title shown in the Settings dialog
22+
setCategory(Constants::LLAMACPP_GENERAL_OPTIONS_CATEGORY);
23+
setSettingsProvider([] { return &LlamaCpp::settings(); });
24+
setWidgetCreator([] { return new LlamaCpp::ToolsSettingsWidget; });
25+
}
26+
27+
// The static instance makes the page appear automatically.
28+
1729
static void initEnableAspect(BoolAspect &enableLlamaCpp)
1830
{
1931
enableLlamaCpp.setSettingsKey(Constants::ENABLE_LLAMACPP);
@@ -25,6 +37,8 @@ static void initEnableAspect(BoolAspect &enableLlamaCpp)
2537

2638
LlamaSettings &settings()
2739
{
40+
static ToolsSettingsPage theToolsPage;
41+
2842
static LlamaSettings settings;
2943
return settings;
3044
}
@@ -372,16 +386,19 @@ LlamaSettings::LlamaSettings()
372386
showTokensPerSecond.setDefaultValue(false);
373387
showTokensPerSecond.setToolTip(Tr::tr("Show tokens per second in the chat UI."));
374388

375-
tools.setSettingsKey("LlamaCpp.Tools");
376-
389+
//
390+
// Tools
391+
//
377392
const QStringList creatorsList = ToolFactory::instance().creatorsList();
378-
QStringList toolDefinitions;
379-
for (const QString &toolName : creatorsList) {
380-
std::unique_ptr<Tool> tool = ToolFactory::instance().create(toolName);
381-
toolDefinitions << tool->toolDefinition();
382-
}
393+
enabledToolsList.setSettingsKey("EnabledToolsList");
394+
enabledToolsList.setDefaultValue(creatorsList);
383395

384-
tools.setDefaultValue(toolDefinitions);
396+
toolsEnabled.setSettingsKey("ToolsEnabled");
397+
toolsEnabled.setDefaultValue(false);
398+
toolsEnabled.setDisplayName(Tr::tr("Enable Tools in Chat"));
399+
toolsEnabled.setLabelText(Tr::tr("Enable Tools in Chat"));
400+
toolsEnabled.setToolTip(
401+
Tr::tr("If checked the chat will start with the Tools button turned on."));
385402

386403
initEnableAspect(enableLlamaCpp);
387404

@@ -428,6 +445,7 @@ LlamaSettings::LlamaSettings()
428445
dry_penalty_last_n.setEnabler(&enableLlamaCpp);
429446
max_tokens.setEnabler(&enableLlamaCpp);
430447
customJson.setEnabler(&enableLlamaCpp);
448+
toolsEnabled.setEnabler(&enableLlamaCpp);
431449

432450
setLayouter([this] {
433451
using namespace Layouting;
@@ -484,6 +502,7 @@ LlamaSettings::LlamaSettings()
484502
Row {dry_penalty_last_n}, br,
485503
hr, br,
486504
showTokensPerSecond, br,
505+
toolsEnabled, br,
487506
customJson, br,
488507
},
489508
};

llamasettings.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <coreplugin/dialogs/ioptionspage.h>
34
#include <utils/aspects.h>
45

56
namespace ProjectExplorer {
@@ -61,7 +62,8 @@ class LlamaSettings : public Utils::AspectContainer
6162
Utils::StringAspect customJson{this};
6263
Utils::BoolAspect showTokensPerSecond{this};
6364

64-
Utils::StringListAspect tools{this};
65+
Utils::StringListAspect enabledToolsList{this};
66+
Utils::BoolAspect toolsEnabled{this};
6567
};
6668

6769
LlamaSettings &settings();
@@ -80,4 +82,10 @@ class LlamaProjectSettings : public Utils::AspectContainer
8082
Utils::BoolAspect useGlobalSettings{this};
8183
};
8284

85+
class ToolsSettingsPage : public Core::IOptionsPage
86+
{
87+
public:
88+
ToolsSettingsPage();
89+
};
90+
8391
} // namespace LlamaCpp

0 commit comments

Comments
 (0)