From 86ec591226a431af3048ad8f144628555eb3fe8e Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Sun, 11 Feb 2024 13:52:06 +0100 Subject: [PATCH] Adding rewritten knowledge lookup functionality via CLI. --- app/src/qt/cli_n_breadcrumbs_presenter.cpp | 27 +++-- app/src/qt/cli_n_breadcrumbs_view.cpp | 25 +---- app/src/qt/cli_n_breadcrumbs_view.h | 10 +- app/src/qt/dialogs/run_tool_dialog.cpp | 121 +++++++++------------ app/src/qt/dialogs/run_tool_dialog.h | 16 +-- app/src/qt/main_window_presenter.cpp | 89 +++++++-------- app/src/qt/main_window_presenter.h | 11 +- lib/src/config/configuration.cpp | 2 + lib/src/config/configuration.h | 75 ++++++++++--- 9 files changed, 187 insertions(+), 189 deletions(-) diff --git a/app/src/qt/cli_n_breadcrumbs_presenter.cpp b/app/src/qt/cli_n_breadcrumbs_presenter.cpp index 18ccbdd5..b1a417cb 100644 --- a/app/src/qt/cli_n_breadcrumbs_presenter.cpp +++ b/app/src/qt/cli_n_breadcrumbs_presenter.cpp @@ -71,9 +71,9 @@ void CliAndBreadcrumbsPresenter::handleCliTextChanged(const QString& text) "" "
Examples:" "
"
-                    "
/notebook by tag TODO" + "
/ find notebook by tag TODO" "
@arxiv LLM" - "
>emojis" + "
> emojis" //"
: explain in simple terms SELECTED" "
" ) @@ -91,7 +91,7 @@ void CliAndBreadcrumbsPresenter::handleCliTextChanged(const QString& text) } else if(command.startsWith(CliAndBreadcrumbsView::CHAR_KNOW)) { MF_DEBUG(" @ HELP knowledge" << endl); if(command.size()<=2) { - view->updateCompleterModel(CliAndBreadcrumbsView::HELP_KNOW_CMDS); + view->updateCompleterModel(view->HELP_KNOW_CMDS); } return; } else if(command.startsWith(CliAndBreadcrumbsView::CHAR_CMD)) { @@ -183,28 +183,27 @@ void CliAndBreadcrumbsPresenter::executeCommand() // mainPresenter->getStatusBar()->showInfo(tr("Notebook ")+QString::fromStdString(outlines->front()->getName())); // mainPresenter->getStatusBar()->showInfo(tr("Notebook not found: ") += QString(name.c_str())); return; - } else + } else // knowledge lookup in the CLI: // - @wikipedia ... opens tool dialog with Wikipedi SELECTED in the dropdown // - @wikipedia llm ... opens directly https://wikipedia.org if(command.startsWith(CliAndBreadcrumbsView::CHAR_KNOW)) { - for(auto c:CliAndBreadcrumbsView::HELP_KNOW_CMDS) { - QString toolName = command.mid(1, c.size()-1); + for(auto c:view->HELP_KNOW_CMDS) { + QString toolId = command.mid(1, c.size()-1); if(command.startsWith(c)) { - QString phrase = command.mid(1, c.size()); + QString phrase = command.mid(1 + c.size()); MF_DEBUG( - " executing: knowledge recherche of '" - << phrase.toStdString() + " executing: knowledge recherche of phrase '" + << phrase.toStdString() << "' using command '" << c.toStdString() << "' and tool '" - << toolName.toStdString() << "'" << endl); - if(phrase.size() > 1 && phrase.startsWith(" ")) { - phrase = phrase.mid(1); - mainPresenter->doActionOpenRunToolDialog(phrase, toolName, false); + << toolId.toStdString() << "'" << endl); + if(phrase.size() > 1) { + mainPresenter->doActionOpenRunToolDialog(phrase, toolId, false); mainPresenter->handleRunTool(); } else { // search phrase is empty - mainPresenter->doActionOpenRunToolDialog(phrase, toolName); + mainPresenter->doActionOpenRunToolDialog(phrase, toolId); } return; } diff --git a/app/src/qt/cli_n_breadcrumbs_view.cpp b/app/src/qt/cli_n_breadcrumbs_view.cpp index 61319f3c..be40a553 100644 --- a/app/src/qt/cli_n_breadcrumbs_view.cpp +++ b/app/src/qt/cli_n_breadcrumbs_view.cpp @@ -141,26 +141,6 @@ const QStringList CliAndBreadcrumbsView::HELP_FIND_CMDS = QStringList() const QString CliAndBreadcrumbsView::CHAR_KNOW = "@"; -// knowledge recherche uses current context / selected entity to lookup the knowledge -const QString CliAndBreadcrumbsView::CMD_KNOW_WIKIPEDIA - = "@wikipedia"; -const QString CliAndBreadcrumbsView::CMD_KNOW_ARXIV - = "@arxiv"; -const QString CliAndBreadcrumbsView::CMD_KNOW_STACK_OVERFLOW - = "@stackoverflow"; -const QString CliAndBreadcrumbsView::CMD_KNOW_DUCK - = "@duckduckgo"; -const QString CliAndBreadcrumbsView::CMD_KNOW_GITHUB - = "@github"; - -const QStringList CliAndBreadcrumbsView::HELP_KNOW_CMDS = QStringList() - << CMD_KNOW_WIKIPEDIA - << CMD_KNOW_ARXIV - << CMD_KNOW_STACK_OVERFLOW - << CMD_KNOW_DUCK - << CMD_KNOW_GITHUB - ; - const QString CliAndBreadcrumbsView::CHAR_CMD = ">"; @@ -220,6 +200,11 @@ CliAndBreadcrumbsView::CliAndBreadcrumbsView(QWidget* parent, bool zenMode) : QWidget(parent), zenMode{zenMode} { + HELP_KNOW_CMDS = QStringList(); + for(const auto& toolName:KnowledgeTool::getToolIds()) { + HELP_KNOW_CMDS << (CHAR_KNOW + QString::fromStdString(toolName)); + } + setFixedHeight(this->fontMetrics().height()*1.5); QHBoxLayout* layout = new QHBoxLayout(this); diff --git a/app/src/qt/cli_n_breadcrumbs_view.h b/app/src/qt/cli_n_breadcrumbs_view.h index ed95a4af..dd2536a6 100644 --- a/app/src/qt/cli_n_breadcrumbs_view.h +++ b/app/src/qt/cli_n_breadcrumbs_view.h @@ -23,6 +23,7 @@ #include "look_n_feel.h" #include "cli_n_breadcrumbs_presenter.h" +#include "../../lib/src/config/configuration.h" namespace m8r { @@ -103,14 +104,7 @@ class CliAndBreadcrumbsView : public QWidget static const QString CHAR_KNOW; - static const QString CMD_KNOW_WIKIPEDIA; - static const QString CMD_KNOW_ARXIV; - static const QString CMD_KNOW_STACK_OVERFLOW; - static const QString CMD_KNOW_DUCK; - static const QString CMD_KNOW_GITHUB; - static const QString CMD_KNOW_BARD; - - static const QStringList HELP_KNOW_CMDS; + QStringList HELP_KNOW_CMDS; // command diff --git a/app/src/qt/dialogs/run_tool_dialog.cpp b/app/src/qt/dialogs/run_tool_dialog.cpp index a4ff2a25..9640bd13 100644 --- a/app/src/qt/dialogs/run_tool_dialog.cpp +++ b/app/src/qt/dialogs/run_tool_dialog.cpp @@ -25,32 +25,18 @@ using namespace std; RunToolDialog::RunToolDialog(QWidget* parent) : QDialog(parent) { - vector toolNames = { - QString{TOOL_ARXIV}, - QString{TOOL_CHAT_GPT_WEB}, - QString{TOOL_DEEPL}, - QString{TOOL_DUCKDUCKGO}, - QString{TOOL_GOOGLE_BARD}, - QString{TOOL_GOOGLE_SEARCH}, - QString{TOOL_GH_REPOS}, - QString{TOOL_GH_TOPICS}, - QString{TOOL_WIKIPEDIA} - }; - - // UI - phraseLabel = new QLabel{tr("Phrase:"), parent}; phraseEdit = new QLineEdit{parent}; toolLabel = new QLabel{tr("Knowledge source:"), parent}; toolCombo = new QComboBox{this}; - for(QString toolName:toolNames) { - toolCombo->addItem(toolName); + for(string toolId: KnowledgeTool::getToolIds()) { + toolCombo->addItem( + getToolNameForToolId(toolId), + QString::fromStdString(toolId)); } - // TODO change of the tool changes the template - templateLabel = new QLabel{tr("Template:"), parent}; templateEdit = new QLineEdit{parent}; @@ -98,68 +84,63 @@ RunToolDialog::~RunToolDialog() { } -void RunToolDialog::show() +QString RunToolDialog::getToolNameForToolId(std::string toolId) const { - QDialog::show(); + if(KnowledgeTool::ARXIV == toolId) { + return tr("arXiv"); + } else if(KnowledgeTool::WIKIPEDIA == toolId) { + return tr("Wikipedia"); + } else if(KnowledgeTool::GH_REPOS == toolId) { + return tr("GitHub Repositories"); + } else if(KnowledgeTool::GH_CODE == toolId) { + return tr("GitHub Code"); + } else if(KnowledgeTool::DUCKDUCKGO == toolId) { + return tr("DuckDuckGo"); + } else if(KnowledgeTool::GOOGLE == toolId) { + return tr("Google"); + } else if(KnowledgeTool::STACK_OVERFLOW == toolId) { + return tr("StackOverflow"); + } else if(KnowledgeTool::CPP == toolId) { + return tr("CPP reference"); + } else if(KnowledgeTool::PYTHON == toolId) { + return tr("Python documentation"); + } + + // no suitable name available + return QString::fromStdString(toolId); } -QString RunToolDialog::getTemplateTextForToolName(string selectedTool) const -{ - if(selectedTool == TOOL_ARXIV) { - QString templateText{"https://arxiv.org/search/?query="}; - templateText.append(TOOL_PHRASE); - return templateText; - } else if(selectedTool == TOOL_DEEPL) { - return QString{"https://www.deepl.com/en/translator"}; - } else if(selectedTool == TOOL_STACK_OVERFLOW) { - QString templateText{"https://stackoverflow.com/search?q="}; - templateText.append(TOOL_PHRASE); - return templateText; - } else if(selectedTool == TOOL_DUCKDUCKGO) { - QString templateText{"https://www.duckduckgo.com/?q="}; - templateText.append(TOOL_PHRASE); - return templateText; - } else if(selectedTool == TOOL_GH_TOPICS) { - // TODO fix search URL - QString templateText{"https://www.github.com/search?q="}; - templateText.append(TOOL_PHRASE); - return templateText; - } else if(selectedTool == TOOL_GH_REPOS) { - // TODO fix search URL - QString templateText{"https://www.github.com/search?q="}; - templateText.append(TOOL_PHRASE); - return templateText; - } else if(selectedTool == TOOL_CHAT_GPT_WEB) { - return QString{"https://chat.openai.com/"}; - } else if(selectedTool == TOOL_GOOGLE_BARD) { - return QString{"https://bard.google.com/chat"}; - } else if(selectedTool == TOOL_GOOGLE_SEARCH) { - QString temlateText{"https://www.google.com/search?q="}; - temlateText.append(TOOL_PHRASE); - return temlateText; - } else if(selectedTool == TOOL_WIKIPEDIA) { - // TODO: URL - QString temlateText{"https://en.wikipedia.org/w/index.php?search="}; - temlateText.append(TOOL_PHRASE); - return temlateText; +bool RunToolDialog::selectToolById(std::string toolId) { + MF_DEBUG( + "RunToolDialog::selectToolById(" << toolId << ") in variantData: " << std::endl); + + QVariant desiredValue = QVariant::fromValue( + QString::fromStdString(toolId)); + int index = this->toolCombo->findData(desiredValue, Qt::UserRole); + if(index != -1) { + this->toolCombo->setCurrentIndex(index); + return true; } - string msg{ - "Tool '" + selectedTool + "' to search/explain/process " - "the phrase is not supported."}; - QMessageBox msgBox{ - QMessageBox::Critical, - QObject::tr("Unsupported Knowledge Tool"), - QObject::tr(msg.c_str()), - }; + MF_DEBUG( + "ERROR: RunToolDialog::setSelectedToolId() - toolId '" + << toolId << "' not found!" << std::endl); + return false; +} - return QString{}; +void RunToolDialog::show() +{ + QDialog::show(); } -void RunToolDialog::handleChangeToolCombo(const QString& text) { +void RunToolDialog::handleChangeToolCombo(const QString& text) +{ MF_DEBUG("Tool changed: " << text.toStdString() << endl); - this->templateEdit->setText(getTemplateTextForToolName(text.toStdString())); + this->templateEdit->setText( + QString::fromStdString( + KnowledgeTool::getUrlTemplateForToolId( + text.toStdString()))); } } // m8r namespace diff --git a/app/src/qt/dialogs/run_tool_dialog.h b/app/src/qt/dialogs/run_tool_dialog.h index 8f0d488c..79d7febc 100644 --- a/app/src/qt/dialogs/run_tool_dialog.h +++ b/app/src/qt/dialogs/run_tool_dialog.h @@ -23,6 +23,8 @@ #include "../../lib/src/config/configuration.h" +#include "../model_meta_definitions.h" + namespace m8r { class RunToolDialog : public QDialog @@ -51,9 +53,9 @@ class RunToolDialog : public QDialog RunToolDialog& operator =(const RunToolDialog&&) = delete; ~RunToolDialog(); - void show(); + QString getToolNameForToolId(std::string toolId) const; - QString getTemplateTextForToolName(std::string selectedTool) const; + void show(); QPushButton* getRunButton() const { return runButton; } QString getSelectedTool() const { @@ -61,12 +63,12 @@ class RunToolDialog : public QDialog this->toolCombo->currentIndex() ); } - void setSelectedTool(QString toolName) { - int index = this->toolCombo->findText(toolName); - if(index != -1) { - this->toolCombo->setCurrentIndex(index); - } + std::string getSelectedToolId() const { + int currentIndex = this->toolCombo->currentIndex(); + QVariant variantData = this->toolCombo->itemData(currentIndex, Qt::UserRole); + return variantData.toString().toStdString(); } + bool selectToolById(std::string toolId); QString getTemplateText() const { return this->templateEdit->text(); } diff --git a/app/src/qt/main_window_presenter.cpp b/app/src/qt/main_window_presenter.cpp index 0c422332..62aca8bd 100644 --- a/app/src/qt/main_window_presenter.cpp +++ b/app/src/qt/main_window_presenter.cpp @@ -1798,15 +1798,27 @@ void MainWindowPresenter::doActionEditPasteImageData(QImage image) void MainWindowPresenter::doActionOpenRunToolDialog( QString& phrase, - QString& toolName, + QString& toolId, bool openDialog ) { - MF_DEBUG("SIGNAL handled: open run tool dialog..."); + MF_DEBUG("SIGNAL handled: open run tool dialog..." << endl); this->runToolDialog->setPhraseText(phrase); - this->runToolDialog->setSelectedTool(toolName); - QString templateText = this->runToolDialog->getTemplateTextForToolName( - this->runToolDialog->getSelectedTool().toStdString()); + if(!this->runToolDialog->selectToolById(toolId.toStdString())) { + QMessageBox::critical( + &view, + tr("Run Knowledge Tool Error"), + tr("Unknown tool to run '%1'.").arg(toolId)); + return; + } + QString templateText = + QString::fromStdString( + KnowledgeTool::getUrlTemplateForToolId( + this->runToolDialog->getSelectedToolId())); if(templateText.length() == 0) { + QMessageBox::critical( + &view, + tr("Open Knowledge Tool Dialog Error"), + tr("Unable to construct URL to open for unknown tool '%1'.").arg(toolId)); return; } this->runToolDialog->setTemplateText(templateText); @@ -1840,7 +1852,7 @@ void MainWindowPresenter::handleRunTool() // phrase replace @ template > get command, if invalid, then fallback QString command = templateText.replace( - QString{TOOL_PHRASE}, phrase + QString::fromStdString(KnowledgeTool::TOOL_PHRASE), phrase ); // RUN tool @@ -1962,38 +1974,7 @@ void MainWindowPresenter::doActionOutlineNew() ); } -void MainWindowPresenter::doActionArxivToolbar() -{ - handleLeftToolbarAction(TOOL_ARXIV); -} - -void MainWindowPresenter::doActionWikipediaToolbar() -{ - handleLeftToolbarAction(TOOL_WIKIPEDIA); -} - -void MainWindowPresenter::doActionStackOverflowToolbar() -{ - handleLeftToolbarAction(TOOL_STACK_OVERFLOW); -} - -void MainWindowPresenter::doActionDuckDuckGoToolbar() -{ - handleLeftToolbarAction(TOOL_DUCKDUCKGO); -} - -void MainWindowPresenter::doActionGitHubToolbar() -{ - handleLeftToolbarAction(TOOL_GH_REPOS); -} - -void MainWindowPresenter::doActionBardToolbar() -{ - handleLeftToolbarAction(TOOL_GOOGLE_BARD); -} - -// TODO remove when code reused by Wingman and @ CLI -void MainWindowPresenter::handleLeftToolbarAction(string selectedTool) +void MainWindowPresenter::handleKnowledgeToolAction(string selectedTool) { // get PHRASE from the active context: // - N editor: get word under cursor OR selected text @@ -2042,17 +2023,29 @@ void MainWindowPresenter::handleLeftToolbarAction(string selectedTool) } // use phrase to RUN the tool - QString templateText - = this->runToolDialog->getTemplateTextForToolName(selectedTool); + string templateText + = KnowledgeTool::getUrlTemplateForToolId(selectedTool); MF_DEBUG( "Run tool: " - << phrase.toStdString() << " -> " - << templateText.toStdString() << " -> " - << selectedTool << endl + << selectedTool << " + " + << phrase.toStdString() << " + " + << templateText << endl ); + if(templateText.empty()) { + QMessageBox::critical( + &view, + tr("Run Knowledge Tool Error"), + tr("Unable to construct URL to open for unknown tool '%1'.").arg( + QString::fromStdString(selectedTool)) + ); + return; + } + // phrase replace @ template > get command, if invalid, then fallback - QString command = templateText.replace(QString{TOOL_PHRASE}, phrase); + QString command = QString::fromStdString(templateText).replace( + QString::fromStdString(KnowledgeTool::TOOL_PHRASE), + phrase); MF_DEBUG("Run tool: command '" << command.toStdString() << "'" << endl); QDesktopServices::openUrl(QUrl{command}); } @@ -2846,7 +2839,7 @@ void MainWindowPresenter::doActionNoteExternalEdit() "Error: unable to run external editor as C++ command processor " "is not available" }; - MF_DEBUG(errorMessage); + MF_DEBUG(errorMessage << endl); statusBar->showError(errorMessage); QMessageBox::critical( &view, @@ -3000,7 +2993,7 @@ void MainWindowPresenter::doActionNoteForget() void MainWindowPresenter::doActionNoteExtract() { - // TODO distinquish HEADER and NOTE - different places from where to get text + // TODO distinguish HEADER and NOTE - different places from where to get text if(orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_OUTLINE_HEADER) || orloj->isFacetActive(OrlojPresenterFacets::FACET_EDIT_NOTE) @@ -3640,11 +3633,11 @@ void MainWindowPresenter::handleCreateOrganizer() Organizer* o{nullptr}; if(newOrganizerDialog->getOrganizerToEdit()) { - MF_DEBUG("Updating organizer..."); + MF_DEBUG("Updating organizer..." << endl); o = newOrganizerDialog->getOrganizerToEdit(); o->setName(newOrganizerDialog->getOrganizerName().toStdString()); } else { - MF_DEBUG("Creating organizer..."); + MF_DEBUG("Creating organizer..." << endl); if(Organizer::OrganizerType::EISENHOWER_MATRIX == newOrganizerDialog->getOrganizerType()) { o = new EisenhowerMatrix( newOrganizerDialog->getOrganizerName().toStdString() diff --git a/app/src/qt/main_window_presenter.h b/app/src/qt/main_window_presenter.h index 70969796..1b87136d 100644 --- a/app/src/qt/main_window_presenter.h +++ b/app/src/qt/main_window_presenter.h @@ -362,20 +362,13 @@ public slots: void doActionEditFindAgain(); void doActionEditWordWrapToggle(); void doActionEditPasteImageData(QImage image); - void doActionOpenRunToolDialog(QString& phrase, QString& tool, bool showDialog=true); + void doActionOpenRunToolDialog(QString& phrase, QString& toolId, bool showDialog=true); void handleRunTool(); void doActionToggleLiveNotePreview(); void doActionNameDescFocusSwap(); void doActionSpellCheck(); // actions - // TODO remake to CLI or REMOVE tools toolbar - void handleLeftToolbarAction(std::string selectedTool); - void doActionArxivToolbar(); - void doActionWikipediaToolbar(); - void doActionStackOverflowToolbar(); - void doActionDuckDuckGoToolbar(); - void doActionGitHubToolbar(); - void doActionBardToolbar(); + void handleKnowledgeToolAction(std::string selectedTool); // help void doActionHelpDocumentation(); void doActionHelpWeb(); diff --git a/lib/src/config/configuration.cpp b/lib/src/config/configuration.cpp index 47a08565..ea622348 100644 --- a/lib/src/config/configuration.cpp +++ b/lib/src/config/configuration.cpp @@ -29,6 +29,8 @@ using namespace m8r::filesystem; namespace m8r { +const string KnowledgeTool::TOOL_PHRASE = string{"<>"}; + // non-primitive constants initializations const string Configuration::DEFAULT_ACTIVE_REPOSITORY_PATH = string{FILE_PATH_M8R_REPOSITORY}; const string Configuration::DEFAULT_STARTUP_VIEW_NAME = string{DEFAULT_STARTUP_VIEW}; diff --git a/lib/src/config/configuration.h b/lib/src/config/configuration.h index 05f6ef84..c8579aad 100644 --- a/lib/src/config/configuration.h +++ b/lib/src/config/configuration.h @@ -113,21 +113,70 @@ constexpr const auto UI_DEFAULT_HTML_CSS_THEME = UI_HTML_THEME_CSS_LIGHT; constexpr const auto UI_DEFAULT_EDITOR_FONT = "Monospace,10"; constexpr const auto UI_DEFAULT_FONT_POINT_SIZE = 10; -constexpr const auto TOOL_PHRASE = "<>"; - -constexpr const auto TOOL_ARXIV = "arXiv"; -constexpr const auto TOOL_DUCKDUCKGO = "DuckDuckGo"; -constexpr const auto TOOL_DEEPL = "DeepL web"; -constexpr const auto TOOL_STACK_OVERFLOW = "StackOverflow"; -constexpr const auto TOOL_GH_REPOS = "GitHub repositories"; -constexpr const auto TOOL_GH_TOPICS = "GitHub topics"; -constexpr const auto TOOL_GOOGLE_BARD = "Google Bard"; -constexpr const auto TOOL_GOOGLE_SEARCH = "Google Search"; -constexpr const auto TOOL_CHAT_GPT_WEB = "OpenAI chatGPT web"; -constexpr const auto TOOL_WIKIPEDIA = "Wikipedia"; +struct KnowledgeTool +{ + static const std::string TOOL_PHRASE; + + // knowledge tools IDs + static constexpr const auto ARXIV = "arxiv"; + static constexpr const auto WIKIPEDIA = "wikipedia"; + static constexpr const auto GH_REPOS = "github-repositories"; + static constexpr const auto GH_CODE = "github-code"; + static constexpr const auto STACK_OVERFLOW = "stackoverflow"; + static constexpr const auto DUCKDUCKGO = "duckduckgo"; + static constexpr const auto GOOGLE = "google"; + static constexpr const auto CPP = "cpp"; + static constexpr const auto PYTHON = "python"; + + std::string id; + std::string name; + std::string urlTemplate; + + KnowledgeTool( + const std::string& id, const std::string& name, const std::string& urlTemplate) + : id(id), name(name), urlTemplate(urlTemplate) {} + + static std::vector getToolIds() { + return { + ARXIV, + WIKIPEDIA, + GH_REPOS, + GH_CODE, + STACK_OVERFLOW, + DUCKDUCKGO, + GOOGLE, + CPP, + PYTHON + }; + } -constexpr const auto ENV_VAR_OPENAI_API_KEY = "MINDFORGER_OPENAI_API_KEY"; + static std::string getUrlTemplateForToolId(const std::string& toolId) { + if (toolId == ARXIV) { + return "https://arxiv.org/search/?query=" + TOOL_PHRASE; + } else if (toolId == WIKIPEDIA) { + return "https://en.wikipedia.org/w/index.php?search=" + TOOL_PHRASE; + } else if (toolId == GH_REPOS) { + return "https://www.github.com/search?type=repositories&q=" + TOOL_PHRASE; + } else if (toolId == GH_CODE) { + return "https://www.github.com/search?type=code&q=" + TOOL_PHRASE; + } else if (toolId == DUCKDUCKGO) { + return "https://www.duckduckgo.com/?q=" + TOOL_PHRASE; + } else if (toolId == GOOGLE) { + return "https://www.google.com/search?q=" + TOOL_PHRASE; + } else if (toolId == STACK_OVERFLOW) { + return "https://stackoverflow.com/search?q=" + TOOL_PHRASE; + } else if (toolId == CPP) { + return "https://duckduckgo.com/?sites=cppreference.com&ia=web&q=" + TOOL_PHRASE; + } else if (toolId == PYTHON) { + return "https://docs.python.org/3.11/search.html?q=" + TOOL_PHRASE; + } + return ""; + } +}; + +// Wingman LLM models API keys +constexpr const auto ENV_VAR_OPENAI_API_KEY = "MINDFORGER_OPENAI_API_KEY"; // improve platform/language specific constexpr const auto DEFAULT_NEW_OUTLINE = "# New Markdown File\n\nThis is a new Markdown file created by MindForger.\n\n#Section 1\nThe first section.\n\n";