Perform tool calls with json.

This commit is contained in:
Bartosz Taudul
2025-06-09 21:25:26 +02:00
parent 1b24f60ac1
commit 845933040d
4 changed files with 60 additions and 73 deletions

View File

@@ -26,16 +26,13 @@ The user is asking about the weather in San Francisco. I need to use the weather
2. *Tool Usage (`<tool>`):*
- If, in the `<think>` block, you decide you need to use a tool, the next block generated *MUST* be a `<tool>` block.
- The tag name MUST be exactly `tool`.
- The first line inside the `<tool>` block *MUST* contain the *exact function name* from the list of available tools.
- If the function requires parameters, provide them on subsequent lines, *one parameter per line*. Provide parameters in plain form, *without quotation marks*.
- *After generating a `<tool>` block, you MUST END YOUR RESPONSE FOR THIS TURN.* Do not generate any other text or tags after the `<tool>` block. The system will process this tool call and provide you with the result in the next step.
- Example:
- The tool name and its parameters (if applicable) must be passed as a json data. For example:
<think>
The user is asking about the weather in San Francisco. I need to use the weather checking tool. The function name is 'check_weather', the parameter is the city name.
The user is asking about the weather in San Francisco. I need to use the weather checking tool. The tool name is 'check_weather', the parameter is the city name.
</think>
<tool>
check_weather
San Francisco
{"tool": "check_weather", "city": "San Francisco"}
</tool>
3. *Tool Output (`<tool_output>`):*

View File

@@ -733,20 +733,6 @@ void TracyLlm::SendMessage( std::unique_lock<std::mutex>& lock )
}
}
static std::vector<std::string> SplitLines( const std::string& str )
{
std::vector<std::string> lines;
auto pos = 0;
while( pos < str.size() )
{
auto next = str.find( '\n', pos );
if( next == std::string::npos ) next = str.size();
if( pos != next ) lines.emplace_back( str.substr( pos, next - pos ) );
pos = next + 1;
}
return lines;
}
bool TracyLlm::OnResponse( const nlohmann::json& json )
{
std::unique_lock lock( m_lock );
@@ -804,24 +790,29 @@ bool TracyLlm::OnResponse( const nlohmann::json& json )
if( end != std::string::npos )
{
while( end > pos && str[end-1] == '\n' ) end--;
auto data = str.substr( pos, end - pos );
auto lines = SplitLines( data );
if( !lines.empty() )
const auto tool = str.substr( pos, end - pos );
lock.unlock();
TracyLlmTools::ToolReply reply;
try
{
isTool = true;
auto tool = lines[0];
lines.erase( lines.begin() );
lock.unlock();
const auto reply = m_tools->HandleToolCalls( tool, lines, *m_api, m_api->GetModels()[m_modelIdx].contextSize, m_embedIdx >= 0 );
auto output = "<tool_output>\n" + reply.reply;
lock.lock();
AddMessage( std::move( output ), "user" );
m_jobs.emplace_back( WorkItem {
.task = Task::SendMessage,
.callback = nullptr
} );
m_cv.notify_all();
auto json = nlohmann::json::parse( tool );
reply = m_tools->HandleToolCalls( json, *m_api, m_api->GetModels()[m_modelIdx].contextSize, m_embedIdx >= 0 );
}
catch( const nlohmann::json::exception& e )
{
reply.reply = e.what();
}
isTool = true;
auto output = "<tool_output>\n" + reply.reply;
lock.lock();
AddMessage( std::move( output ), "user" );
m_jobs.emplace_back( WorkItem {
.task = Task::SendMessage,
.callback = nullptr
} );
m_cv.notify_all();
}
}
}

View File

@@ -181,51 +181,49 @@ TracyLlmTools::~TracyLlmTools()
CancelManualEmbeddings();
}
TracyLlmTools::ToolReply TracyLlmTools::HandleToolCalls( const std::string& name, const std::vector<std::string>& args, TracyLlmApi& api, int contextSize, bool hasEmbeddingsModel )
#define Param(name) json[name].get_ref<const std::string&>()
TracyLlmTools::ToolReply TracyLlmTools::HandleToolCalls( const nlohmann::json& json, TracyLlmApi& api, int contextSize, bool hasEmbeddingsModel )
{
m_ctxSize = contextSize;
if( name == "fetch_web_page" )
try
{
if( args.empty() ) return { .reply = "Missing URL argument" };
return { .reply = FetchWebPage( args[0] ) };
auto name = json["tool"].get_ref<const std::string&>();
if( name == "search_wikipedia" )
{
return SearchWikipedia( Param( "query" ), Param( "language" ) );
}
else if( name == "get_wikipedia" )
{
return { .reply = GetWikipedia( Param( "page" ), Param( "language" ) ) };
}
else if( name == "get_dictionary" )
{
return { .reply = GetDictionary( Param( "word" ), Param( "language" ) ) };
}
else if( name == "search_web" )
{
return { .reply = SearchWeb( Param( "query" ) ) };
}
else if( name == "get_webpage" )
{
return { .reply = GetWebpage( Param( "url" ) ) };
}
else if( name == "user_manual" )
{
return { .reply = SearchManual( Param( "query" ), api, hasEmbeddingsModel ) };
}
return { .reply = "Unknown tool call: " + name };
}
if( name == "search_wikipedia" )
catch( const nlohmann::json::exception& e )
{
if( args.empty() ) return { .reply = "Missing search term argument" };
if( args.size() < 2 ) return { .reply = "Missing language argument" };
return SearchWikipedia( args[0], args[1] );
return { .reply = e.what() };
}
if( name == "get_wikipedia" )
{
if( args.empty() ) return { .reply = "Missing page name argument" };
if( args.size() < 2 ) return { .reply = "Missing language argument" };
return { .reply = GetWikipedia( args[0], args[1] ) };
}
if( name == "get_dictionary" )
{
if( args.empty() ) return { .reply = "Missing word argument" };
if( args.size() < 2 ) return { .reply = "Missing language argument" };
return { .reply = GetDictionary( args[0], args[1] ) };
}
if( name == "search_web" )
{
if( args.empty() ) return { .reply = "Missing search term argument" };
return { .reply = SearchWeb( args[0] ) };
}
if( name == "get_webpage" )
{
if( args.empty() ) return { .reply = "Missing URL argument" };
return { .reply = GetWebpage( args[0] ) };
}
if( name == "user_manual" )
{
if( args.empty() ) return { .reply = "Missing search term argument" };
return { .reply = SearchManual( args[0], api, hasEmbeddingsModel ) };
}
return { .reply = "Unknown tool call: " + name };
}
#undef Param
std::string TracyLlmTools::GetCurrentTime() const
{
auto t = time( nullptr );

View File

@@ -1,6 +1,7 @@
#ifndef __TRACYLLMTOOLS_HPP__
#define __TRACYLLMTOOLS_HPP__
#include <nlohmann/json.hpp>
#include <memory>
#include <mutex>
#include <string>
@@ -37,7 +38,7 @@ public:
TracyLlmTools();
~TracyLlmTools();
ToolReply HandleToolCalls( const std::string& name, const std::vector<std::string>& args, TracyLlmApi& api, int contextSize, bool hasEmbeddingsModel );
ToolReply HandleToolCalls( const nlohmann::json& json, TracyLlmApi& api, int contextSize, bool hasEmbeddingsModel );
std::string GetCurrentTime() const;
[[nodiscard]] EmbeddingState GetManualEmbeddingsState() const;