Changes
diff --git a/demo/main.cpp b/demo/main.cpp
index 21fc201..51d7d87 100644
--- a/demo/main.cpp
+++ b/demo/main.cpp
@@ -1,11 +1,11 @@
#include <cstdlib>
#include <iostream>
+#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <variant>
-#include <vector>
#include <agent_smith/agent_smith.hpp>
@@ -30,7 +30,7 @@ void printUsage(std::ostream& output)
<< "\n"
<< "The demo provides a tool for current weather by city.\n"
<< "\n"
- << "Commands: /help, /quit\n";
+ << "Commands: /help, /clear, /stream on, /stream off, /quit\n";
}
agent_smith::ToolSchema weatherSchema()
@@ -85,52 +85,21 @@ queryWeather(nlohmann::json arguments, agent_smith::ToolContext context)
};
}
-void appendToolResults(std::vector<agent_smith::Message>& messages,
- agent_smith::ToolRegistry& tools,
- agent_smith::Runtime& runtime,
- const std::vector<agent_smith::ToolCall>& calls)
+void printToolResult(const agent_smith::ToolMessage& result)
{
- for(const agent_smith::ToolCall& call : calls)
- {
- agent_smith::Tool* tool = tools.find(call.name);
- if(tool == nullptr)
- {
- const std::string content = "unknown tool: " + call.name;
- std::cout << "[tool error: " << content << "]\n";
- messages.emplace_back(agent_smith::ToolMessage{
- .tool_call_id = call.id,
- .name = call.name,
- .content = content,
- .is_error = true,
- });
- continue;
- }
-
- auto result = syncWait(tool->invoke(
- call.arguments,
- agent_smith::ToolContext{
- .call_id = call.id,
- .runtime = &runtime,
- }));
- if(!result)
- {
- std::cout << "[tool error: " << result.error().msg() << "]\n";
- messages.emplace_back(agent_smith::ToolMessage{
- .tool_call_id = call.id,
- .name = call.name,
- .content = result.error().msg(),
- .is_error = true,
- });
- continue;
- }
+ std::cout << (result.is_error ? "[tool error: " : "[tool result: ")
+ << result.content << "]\n";
+}
- std::cout << "[tool result: " << result->content << "]\n";
- messages.emplace_back(agent_smith::ToolMessage{
- .tool_call_id = call.id,
- .name = call.name,
- .content = result->content,
- .is_error = result->is_error,
- });
+void printUsageReport(const agent_smith::Message& message)
+{
+ const auto* assistant =
+ std::get_if<agent_smith::AssistantMessage>(&message);
+ if(assistant != nullptr && assistant->usage)
+ {
+ std::cout << "[usage: prompt=" << assistant->usage->prompt
+ << ", completion=" << assistant->usage->completion
+ << ", total=" << assistant->usage->total << "]\n";
}
}
@@ -195,12 +164,30 @@ int main(int argc, char* argv[])
agent_smith::Runtime runtime;
agent_smith::LlmClient client(runtime, std::move(config));
- agent_smith::ToolRegistry tools;
- tools.add(agent_smith::makeTool(weatherSchema(), queryWeather));
- std::vector<agent_smith::Message> messages;
- std::cout << "Agent Smith " << agent_smith::VERSION
- << " provider test CLI. Enter /help for commands.\n";
+ // Retain at most 64 messages and approximately 8K tokens of history.
+ auto memory = std::make_shared<agent_smith::RollingWindowMemory>(
+ agent_smith::RollingWindowConfig{
+ .max_messages = 64,
+ .max_tokens = 8192,
+ });
+ auto tree = std::make_shared<agent_smith::AgentTreeState>();
+ agent_smith::Agent agent(runtime, client, memory,
+ {.max_iterations = 16, .tree_state = tree});
+ auto registered = agent.addTool(
+ agent_smith::makeTool(weatherSchema(), queryWeather));
+ if(!registered)
+ {
+ std::cerr << "Tool registration failed: "
+ << registered.error().msg() << '\n';
+ return 2;
+ }
+ agent.hooks().on_stream_event = printStreamEvent;
+ agent.hooks().on_tool_result = printToolResult;
+ agent.hooks().on_message = printUsageReport;
+ std::cout << "Agent Smith " << agent_smith::VERSION
+ << " agent CLI. Enter /help for commands.\n";
+ bool stream = true;
std::string prompt;
while(std::cout << "> " << std::flush, std::getline(std::cin, prompt))
{
@@ -213,49 +200,40 @@ int main(int argc, char* argv[])
printUsage(std::cout);
continue;
}
+ if(prompt == "/clear")
+ {
+ memory->clear();
+ tree->iterations.store(0);
+ std::cout << "Conversation cleared.\n";
+ continue;
+ }
+ if(prompt == "/stream on" || prompt == "/stream off")
+ {
+ stream = prompt == "/stream on";
+ std::cout << "Streaming " << (stream ? "on" : "off") << ".\n";
+ continue;
+ }
if(prompt.empty())
{
continue;
}
- const std::size_t message_count = messages.size();
- messages.emplace_back(agent_smith::UserMessage{.content = prompt});
- bool request_failed = false;
- for(std::size_t iteration = 0; iteration < 4; ++iteration)
+ // Each interactive turn starts a fresh tree iteration budget.
+ tree->iterations.store(0);
+ auto result = agent_smith::syncWait(agent.send(
+ agent_smith::AgentRequest{
+ .message = {prompt},
+ .stream = stream,
+ }));
+ if(!result)
{
- auto result = syncWait(client.completeStream(
- {
- .messages = messages,
- .tools = tools.schemas(),
- },
- printStreamEvent));
- if(!result)
- {
- std::cerr << "\nRequest failed: " << result.error().msg()
- << '\n';
- request_failed = true;
- break;
- }
-
- messages.emplace_back(std::move(result->message));
- const auto& assistant =
- std::get<agent_smith::AssistantMessage>(messages.back());
- if(assistant.usage)
- {
- std::cout << "[usage: prompt=" << assistant.usage->prompt
- << ", completion=" << assistant.usage->completion
- << ", total=" << assistant.usage->total << "]\n";
- }
- if(assistant.tool_calls.empty())
- {
- break;
- }
-
- appendToolResults(messages, tools, runtime, assistant.tool_calls);
+ std::cerr << "\nRequest failed: " << result.error().msg()
+ << "\nUse /clear to discard this conversation.\n";
+ continue;
}
- if(request_failed)
+ if(!stream)
{
- messages.resize(message_count);
+ std::cout << result->content << '\n';
}
}