Repository: nomic-ai/gpt4all
File: gpt4all-chat/src/chat.cpp (C++)

Code before:
            ToolCallConstants::CodeInterpreterFunction,
            { param },
            result,
            error,
            errorString
        });

        ++m_consecutiveToolCalls;

        // We limit the number of consecutive toolcalls otherwise we get into a potentially endless loop
        if (m_consecutiveToolCalls < 3 || error == ToolEnums::Error::NoError) {
            resetResponseState();
            emit promptRequested(m_collections); // triggers a new response
            return;
        }
    }

    if (m_generatedName.isEmpty())
        emit generateNameRequested();

    m_consecutiveToolCalls = 0;
    Network::globalInstance()->trackChatEvent("response_complete", {
        {"first", m_firstResponse},
        {"message_count", chatModel()->count()},
        {"$duration", promptResponseMs / 1000.},
    });
    m_firstResponse = false;
}

ModelInfo Chat::modelInfo() const
{
    return m_modelInfo;
}

void Chat::setModelInfo(const ModelInfo &modelInfo)
{
    if (m_modelInfo != modelInfo) {
        m_modelInfo = modelInfo;
        m_needsSave = true;
    } else if (isModelLoaded())
        return;

    emit modelInfoChanged();
    emit modelChangeRequested(modelInfo);
}

void Chat::unloadAndDeleteLater()
{
    if (!isModelLoaded()) {
        deleteLater();
        return;

Review comment (bug):
Removing this will break this graph: https://mixpanel.com/project/2976651/view/3495911/app/boards#id=4885068&editor-card-id=%22report-55731492%22

Is there a problem with response_complete that means that it was not/is no longer useful? I would rather we add/expand events rather than remove them, when possible.

Code after:
    static const QRegularExpression regex("^\\s*```javascript\\s*|\\s*```\\s*$");
    QString code = toolCall;
    code.remove(regex);
    code = code.trimmed();

    // Right now the code interpreter is the only available tool
    Tool *toolInstance = ToolModel::globalInstance()->get(ToolCallConstants::CodeInterpreterFunction);
    Q_ASSERT(toolInstance);
    connect(toolInstance, &Tool::runComplete, this, &Chat::toolCallComplete, Qt::SingleShotConnection);

    // The param is the code
    const ToolParam param = { "code", ToolEnums::ParamType::String, code };
    m_responseInProgress = true;
    emit responseInProgressChanged();
    toolInstance->run({param});
}

void Chat::toolCallComplete(const ToolCallInfo &info)
{
    // Update the current response with meta information about toolcall and re-parent
    m_chatModel->updateToolCall(info);

    ++m_consecutiveToolCalls;

    m_responseInProgress = false;
    emit responseInProgressChanged();

    // We limit the number of consecutive toolcalls otherwise we get into a potentially endless loop
    if (m_consecutiveToolCalls < 3 || info.error == ToolEnums::Error::NoError) {
        resetResponseState();
        emit promptRequested(m_collections); // triggers a new response
        return;
    }

    responseComplete();
}

void Chat::responseComplete()
{
    if (m_generatedName.isEmpty())
        emit generateNameRequested();

    m_responseState = Chat::ResponseStopped;
    emit responseStateChanged();

    m_consecutiveToolCalls = 0;
    m_firstResponse = false;
}

ModelInfo Chat::modelInfo() const
{