mirror of
https://github.com/wolfpld/tracy.git
synced 2026-10-23 17:20:48 +00:00
Take the thinking and tool use context into account in LLM chat rendering.
This commit is contained in:
@@ -430,14 +430,11 @@ void TracyLlm::Draw()
|
||||
if( !line.contains( "role" ) ) break;
|
||||
const auto& roleStr = line["role"].get_ref<const std::string&>();
|
||||
if( roleStr == "system" ) continue;
|
||||
const auto& contentNode = line["content"];
|
||||
if( !contentNode.is_string() ) continue;
|
||||
const auto& content = contentNode.get_ref<const std::string&>();
|
||||
|
||||
TracyLlmChat::TurnRole role = TracyLlmChat::TurnRole::None;
|
||||
if( roleStr == "user" ) role = TracyLlmChat::TurnRole::User;
|
||||
else if( roleStr == "error" ) role = TracyLlmChat::TurnRole::Error;
|
||||
else if( roleStr == "assistant" ) role = TracyLlmChat::TurnRole::Assistant;
|
||||
else if( roleStr == "assistant" || roleStr == "tool" ) role = TracyLlmChat::TurnRole::Assistant;
|
||||
else assert( false );
|
||||
|
||||
if( role == TracyLlmChat::TurnRole::User )
|
||||
@@ -446,7 +443,7 @@ void TracyLlm::Draw()
|
||||
}
|
||||
|
||||
ImGui::PushID( turnIdx++ );
|
||||
if( !m_chatUi->Turn( role, content ) )
|
||||
if( !m_chatUi->Turn( role, line ) )
|
||||
{
|
||||
if( role == TracyLlmChat::TurnRole::Assistant )
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ void TracyLlmChat::End()
|
||||
}
|
||||
}
|
||||
|
||||
bool TracyLlmChat::Turn( TurnRole role, const std::string& content )
|
||||
bool TracyLlmChat::Turn( TurnRole role, const nlohmann::json& json )
|
||||
{
|
||||
bool keep = true;
|
||||
const auto& roleData = roles[(int)role];
|
||||
@@ -166,120 +166,107 @@ bool TracyLlmChat::Turn( TurnRole role, const std::string& content )
|
||||
}
|
||||
else if( role != TurnRole::Assistant )
|
||||
{
|
||||
auto pos = content.find( "<SYSTEM_PROMPT>" );
|
||||
if( pos == std::string::npos )
|
||||
if( json.contains( "content" ) )
|
||||
{
|
||||
auto& content = json["content"].get_ref<const std::string&>();
|
||||
m_markdown.Print( content.c_str(), content.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto str = content;
|
||||
while( ( pos = str.find( "<SYSTEM_PROMPT>" ) ) != std::string::npos )
|
||||
{
|
||||
auto pos2 = str.find( "</SYSTEM_PROMPT>" );
|
||||
str = str.substr( 0, pos ) + str.substr( pos2 + sizeof( "</SYSTEM_PROMPT>" ) - 1 );
|
||||
}
|
||||
m_markdown.Print( str.c_str(), str.size() );
|
||||
}
|
||||
}
|
||||
else if( content.starts_with( "<tool_output>\n" ) )
|
||||
{
|
||||
ThinkScope();
|
||||
if( m_thinkOpen )
|
||||
{
|
||||
ImGui::PushStyleColor( ImGuiCol_Text, ImVec4( 0.5f, 0.5f, 0.5f, 1.f ) );
|
||||
if( content == ForgetMsg )
|
||||
{
|
||||
ImGui::TextUnformatted( ICON_FA_RECYCLE " Tool response removed to save context space" );
|
||||
m_subIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushID( m_subIdx++ );
|
||||
if( ImGui::TreeNode( ICON_FA_REPLY " Tool response..." ) )
|
||||
{
|
||||
ImGui::PushFont( g_fonts.mono, FontNormal );
|
||||
ImGui::TextWrapped( "%s", content.c_str() + sizeof( "<tool_output>\n" ) - 1 );
|
||||
ImGui::PopFont();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_subIdx++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t end = content.size();
|
||||
while( pos < end )
|
||||
if( json.contains( "reasoning_content" ) )
|
||||
{
|
||||
auto posThink = content.find( "<think>", pos );
|
||||
auto posTool = content.find( "<tool>", pos );
|
||||
auto minPos = std::min( posThink, posTool );
|
||||
|
||||
if( pos != minPos )
|
||||
ThinkScope();
|
||||
if( m_thinkOpen )
|
||||
{
|
||||
NormalScope();
|
||||
m_markdown.Print( content.c_str() + pos, std::min( end, minPos ) - pos );
|
||||
auto& reasoning = json["reasoning_content"].get_ref<const std::string&>();
|
||||
PrintThink( reasoning.c_str(), reasoning.size() );
|
||||
}
|
||||
|
||||
pos = minPos;
|
||||
if( pos == std::string::npos ) break;
|
||||
|
||||
if( minPos == posThink )
|
||||
}
|
||||
if( json.contains( "tool_calls" ) )
|
||||
{
|
||||
ThinkScope();
|
||||
if( m_thinkOpen )
|
||||
{
|
||||
pos += sizeof( "<think>" ) - 1;
|
||||
while( content[pos] == '\n' || content[pos] == ' ' ) pos++;
|
||||
auto endThink = content.find( "</think>", pos );
|
||||
if( endThink != pos )
|
||||
auto calls = json["tool_calls"].dump( 2 );
|
||||
PrintToolCall( calls.c_str(), calls.size() );
|
||||
}
|
||||
}
|
||||
if( json.contains( "content" ) )
|
||||
{
|
||||
auto& content = json["content"].get_ref<const std::string&>();
|
||||
if( json["role"].get_ref<const std::string&>() == "tool" )
|
||||
{
|
||||
ThinkScope();
|
||||
if( m_thinkOpen )
|
||||
{
|
||||
ThinkScope();
|
||||
if( m_thinkOpen ) PrintThink( content.c_str() + pos, std::min( end, endThink ) - pos );
|
||||
ImGui::PushStyleColor( ImGuiCol_Text, ImVec4( 0.5f, 0.5f, 0.5f, 1.f ) );
|
||||
if( content == ForgetMsg )
|
||||
{
|
||||
ImGui::TextUnformatted( ICON_FA_RECYCLE " Tool response removed to save context space" );
|
||||
m_subIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& name = json["name"].get_ref<const std::string&>();
|
||||
auto& id = json["tool_call_id"].get_ref<const std::string&>();
|
||||
ImGui::PushID( m_subIdx++ );
|
||||
char buf[1024];
|
||||
snprintf( buf, sizeof( buf ), ICON_FA_REPLY " Tool response (%s/%s)...", name.c_str(), id.substr( 0, 8 ).c_str() );
|
||||
if( ImGui::TreeNode( buf ) )
|
||||
{
|
||||
std::string parsed;
|
||||
try
|
||||
{
|
||||
parsed = nlohmann::json::parse( content.c_str() ).dump( 2 );
|
||||
}
|
||||
catch( nlohmann::json::exception& )
|
||||
{
|
||||
parsed = content;
|
||||
}
|
||||
ImGui::PushFont( g_fonts.mono, FontNormal );
|
||||
ImGui::TextWrapped( "%s", parsed.c_str() );
|
||||
ImGui::PopFont();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if( endThink == std::string::npos ) break;
|
||||
pos = endThink;
|
||||
do
|
||||
else
|
||||
{
|
||||
pos += sizeof( "</think>" ) - 1;
|
||||
while( content[pos] == '\n' || content[pos] == ' ' ) pos++;
|
||||
m_subIdx++;
|
||||
}
|
||||
while( strncmp( content.c_str() + pos, "</think>", sizeof( "</think>" ) - 1 ) == 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( minPos == posTool );
|
||||
pos += sizeof( "<tool>" ) - 1;
|
||||
while( content[pos] == '\n' || content[pos] == ' ' ) pos++;
|
||||
auto endTool = content.find( "</tool>", pos );
|
||||
ThinkScope();
|
||||
if( m_thinkOpen ) PrintToolCall( content.c_str() + pos, std::min( end, endTool ) - pos );
|
||||
if( endTool == std::string::npos ) break;
|
||||
pos = endTool + sizeof( "</tool>" ) - 1;
|
||||
while( content[pos] == '\n' || content[pos] == ' ' ) pos++;
|
||||
if( !content.empty() )
|
||||
{
|
||||
NormalScope();
|
||||
m_markdown.Print( content.c_str(), content.size() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if( ImGui::IsMouseClicked( ImGuiMouseButton_Right ) &&
|
||||
ImGui::IsWindowHovered() &&
|
||||
ImGui::IsMouseHoveringRect( posStart, ImGui::GetCursorScreenPos() + ImVec2( ImGui::GetContentRegionAvail().x, 0 ) ) )
|
||||
if( json.contains( "content" ) )
|
||||
{
|
||||
ImGui::OpenPopup( "ContextMenu" );
|
||||
}
|
||||
if( ImGui::BeginPopup( "ContextMenu" ) )
|
||||
{
|
||||
if( ImGui::Selectable( ICON_FA_CLIPBOARD " Copy" ) )
|
||||
if( ImGui::IsMouseClicked( ImGuiMouseButton_Right ) &&
|
||||
ImGui::IsWindowHovered() &&
|
||||
ImGui::IsMouseHoveringRect( posStart, ImGui::GetCursorScreenPos() + ImVec2( ImGui::GetContentRegionAvail().x, 0 ) ) )
|
||||
{
|
||||
ImGui::SetClipboardText( content.c_str() );
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::OpenPopup( "ContextMenu" );
|
||||
}
|
||||
if( ImGui::BeginPopup( "ContextMenu" ) )
|
||||
{
|
||||
if( ImGui::Selectable( ICON_FA_CLIPBOARD " Copy" ) )
|
||||
{
|
||||
ImGui::SetClipboardText( json["content"].get_ref<const std::string&>().c_str() );
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
return keep;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __TRACYLLMCHAT_HPP__
|
||||
#define __TRACYLLMCHAT_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "TracyMarkdown.hpp"
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
void Begin();
|
||||
void End();
|
||||
|
||||
bool Turn( TurnRole role, const std::string& content );
|
||||
bool Turn( TurnRole role, const nlohmann::json& json );
|
||||
|
||||
private:
|
||||
void NormalScope();
|
||||
|
||||
Reference in New Issue
Block a user