mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-05-30 02:49:12 -04:00
fix: Add handling final argument for OpenAI responses tool calling
This commit is contained in:
@@ -174,14 +174,21 @@ void ClientInterface::sendMessage(
|
||||
auto project = PluginLLMCore::RulesLoader::getActiveProject();
|
||||
|
||||
if (project) {
|
||||
systemPrompt += QString("\n# Active project name: %1").arg(project->displayName());
|
||||
systemPrompt += QString("\n# Active Project path: %1")
|
||||
systemPrompt += QString("\n# Active project: %1").arg(project->displayName());
|
||||
systemPrompt += QString(
|
||||
"\n# Project source root: %1"
|
||||
"\n# All new source files, headers, QML and CMake edits MUST be "
|
||||
"created or modified under this directory. Use absolute paths "
|
||||
"rooted here, or project-relative paths.")
|
||||
.arg(project->projectDirectory().toUrlishString());
|
||||
|
||||
if (auto target = project->activeTarget()) {
|
||||
if (auto buildConfig = target->activeBuildConfiguration()) {
|
||||
systemPrompt += QString("\n# Active Build directory: %1")
|
||||
.arg(buildConfig->buildDirectory().toUrlishString());
|
||||
systemPrompt
|
||||
+= QString(
|
||||
"\n# Build output directory (compiler artifacts only — do NOT "
|
||||
"create or edit source files here): %1")
|
||||
.arg(buildConfig->buildDirectory().toUrlishString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,9 @@ ToolsSettings::ToolsSettings()
|
||||
Tr::tr("Comma-separated list of terminal commands that AI is allowed to execute on Linux. "
|
||||
"Example: git, ls, cat, grep, find, cmake"));
|
||||
allowedTerminalCommandsLinux.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
allowedTerminalCommandsLinux.setDefaultValue("git, ls, cat, grep, find");
|
||||
allowedTerminalCommandsLinux.setDefaultValue(
|
||||
"git, ls, cat, grep, find, pwd, echo, head, tail, wc, which, file, stat, tree, uname, "
|
||||
"date, whoami, hostname");
|
||||
|
||||
allowedTerminalCommandsMacOS.setSettingsKey(Constants::CA_ALLOWED_TERMINAL_COMMANDS_MACOS);
|
||||
allowedTerminalCommandsMacOS.setLabelText(Tr::tr("Allowed Commands (macOS)"));
|
||||
@@ -141,7 +143,9 @@ ToolsSettings::ToolsSettings()
|
||||
Tr::tr("Comma-separated list of terminal commands that AI is allowed to execute on macOS. "
|
||||
"Example: git, ls, cat, grep, find, cmake"));
|
||||
allowedTerminalCommandsMacOS.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
allowedTerminalCommandsMacOS.setDefaultValue("git, ls, cat, grep, find");
|
||||
allowedTerminalCommandsMacOS.setDefaultValue(
|
||||
"git, ls, cat, grep, find, pwd, echo, head, tail, wc, which, file, stat, tree, uname, "
|
||||
"date, whoami, hostname");
|
||||
|
||||
allowedTerminalCommandsWindows.setSettingsKey(Constants::CA_ALLOWED_TERMINAL_COMMANDS_WINDOWS);
|
||||
allowedTerminalCommandsWindows.setLabelText(Tr::tr("Allowed Commands (Windows)"));
|
||||
@@ -149,7 +153,8 @@ ToolsSettings::ToolsSettings()
|
||||
Tr::tr("Comma-separated list of terminal commands that AI is allowed to execute on Windows. "
|
||||
"Example: git, dir, type, findstr, where, cmake"));
|
||||
allowedTerminalCommandsWindows.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||
allowedTerminalCommandsWindows.setDefaultValue("git, dir, type, findstr, where");
|
||||
allowedTerminalCommandsWindows.setDefaultValue(
|
||||
"git, dir, type, findstr, where, echo, whoami, hostname, ver, tree, fc");
|
||||
|
||||
terminalCommandTimeout.setSettingsKey(Constants::CA_TERMINAL_COMMAND_TIMEOUT);
|
||||
terminalCommandTimeout.setLabelText(Tr::tr("Command Timeout (seconds)"));
|
||||
|
||||
2
sources/external/llmqore
vendored
2
sources/external/llmqore
vendored
Submodule sources/external/llmqore updated: ddbc38ffbd...95a7b3ac51
@@ -77,10 +77,20 @@ QFuture<LLMQore::ToolResult> CreateNewFileTool::executeAsync(const QJsonObject &
|
||||
if (!isInProject) {
|
||||
const auto &settings = Settings::toolsSettings();
|
||||
if (!settings.allowAccessOutsideProject()) {
|
||||
const QString projectRoot = Context::ProjectUtils::getProjectRoot();
|
||||
const QString hint = projectRoot.isEmpty()
|
||||
? QStringLiteral(
|
||||
"No project is currently open. Open a project in Qt Creator or "
|
||||
"enable 'Allow file access outside project' in QodeAssist settings.")
|
||||
: QString(
|
||||
"Retry with a path under the active project root: '%1'. The build "
|
||||
"directory is for compiler output only and cannot accept new source "
|
||||
"files. If you really need to write outside the project, enable "
|
||||
"'Allow file access outside project' in QodeAssist settings.")
|
||||
.arg(projectRoot);
|
||||
throw LLMQore::ToolRuntimeError(
|
||||
QString("Error: File path '%1' is not within the current project. "
|
||||
"Enable 'Allow file access outside project' in settings to create files outside project scope.")
|
||||
.arg(absolutePath));
|
||||
QString("Error: File path '%1' is not within the current project. %2")
|
||||
.arg(absolutePath, hint));
|
||||
}
|
||||
LOG_MESSAGE(QString("Creating file outside project scope: %1").arg(absolutePath));
|
||||
}
|
||||
|
||||
@@ -143,10 +143,20 @@ QFuture<LLMQore::ToolResult> EditFileTool::executeAsync(const QJsonObject &input
|
||||
if (!isInProject) {
|
||||
const auto &settings = Settings::toolsSettings();
|
||||
if (!settings.allowAccessOutsideProject()) {
|
||||
const QString projectRoot = Context::ProjectUtils::getProjectRoot();
|
||||
const QString hint = projectRoot.isEmpty()
|
||||
? QStringLiteral(
|
||||
"No project is currently open. Open a project in Qt Creator or "
|
||||
"enable 'Allow file access outside project' in QodeAssist settings.")
|
||||
: QString(
|
||||
"Retry with a path under the active project root: '%1'. The build "
|
||||
"directory is for compiler output only — source files must live under "
|
||||
"the project root. If you really need to edit outside the project, "
|
||||
"enable 'Allow file access outside project' in QodeAssist settings.")
|
||||
.arg(projectRoot);
|
||||
throw LLMQore::ToolRuntimeError(
|
||||
QString("File path '%1' is not within the current project. "
|
||||
"Enable 'Allow file access outside project' in settings to edit files outside the project.")
|
||||
.arg(filePath));
|
||||
QString("File path '%1' is not within the current project. %2")
|
||||
.arg(filePath, hint));
|
||||
}
|
||||
LOG_MESSAGE(QString("Editing file outside project scope: %1").arg(filePath));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QProcess>
|
||||
#include <QPromise>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpression>
|
||||
#include <QSharedPointer>
|
||||
#include <QTimer>
|
||||
|
||||
@@ -45,18 +46,26 @@ QJsonObject ExecuteTerminalCommandTool::parametersSchema() const
|
||||
QJsonObject definition;
|
||||
definition["type"] = "object";
|
||||
|
||||
const QString commandDesc = getCommandDescription();
|
||||
const QStringList allowed = getAllowedCommands();
|
||||
const QString allowedList = allowed.isEmpty() ? "none" : allowed.join(", ");
|
||||
|
||||
QJsonObject properties;
|
||||
properties["command"] = QJsonObject{
|
||||
{"type", "string"},
|
||||
{"description", commandDesc}};
|
||||
{"description",
|
||||
QString("Name of the executable to run, WITHOUT any arguments or flags. "
|
||||
"Must be exactly one of the allowed commands: %1. "
|
||||
"Put every flag and argument in the separate `args` field. "
|
||||
"Correct: command=\"ls\", args=\"-R\". "
|
||||
"Incorrect: command=\"ls -R\" (the whole line in one field will be rejected).")
|
||||
.arg(allowedList)}};
|
||||
|
||||
properties["args"] = QJsonObject{
|
||||
{"type", "string"},
|
||||
{"description",
|
||||
"Optional arguments for the command. Arguments with spaces should be properly quoted. "
|
||||
"Example: '--file \"path with spaces.txt\" --verbose'"}};
|
||||
"Optional arguments and flags for the command, as a single string. Do NOT repeat the "
|
||||
"command name here. Arguments with spaces should be quoted. "
|
||||
"Example: args=\"--file \\\"path with spaces.txt\\\" --verbose\"."}};
|
||||
|
||||
definition["properties"] = properties;
|
||||
definition["required"] = QJsonArray{"command"};
|
||||
@@ -68,14 +77,25 @@ QFuture<LLMQore::ToolResult> ExecuteTerminalCommandTool::executeAsync(const QJso
|
||||
{
|
||||
using LLMQore::ToolResult;
|
||||
|
||||
const QString command = input.value("command").toString().trimmed();
|
||||
const QString args = input.value("args").toString().trimmed();
|
||||
QString command = input.value("command").toString().trimmed();
|
||||
QString args = input.value("args").toString().trimmed();
|
||||
|
||||
if (command.isEmpty()) {
|
||||
LOG_MESSAGE("ExecuteTerminalCommandTool: Command is empty");
|
||||
return QtFuture::makeReadyFuture(ToolResult::error("Error: Command parameter is required."));
|
||||
}
|
||||
|
||||
// Tolerate models that pack the whole command line into `command`. As long as `args` is
|
||||
// empty we can safely split on the first whitespace — the allowlist check still validates
|
||||
// the actual executable name.
|
||||
if (args.isEmpty()) {
|
||||
const int firstSpace = command.indexOf(QRegularExpression("\\s"));
|
||||
if (firstSpace > 0) {
|
||||
args = command.mid(firstSpace + 1).trimmed();
|
||||
command = command.left(firstSpace);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.length() > MAX_COMMAND_LENGTH) {
|
||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command too long (%1 chars)")
|
||||
.arg(command.length()));
|
||||
|
||||
Reference in New Issue
Block a user