From 10a2713465ec68be686b9774aa346244460d799d Mon Sep 17 00:00:00 2001 From: scawful Date: Sat, 4 Oct 2025 03:07:32 -0400 Subject: [PATCH] feat: Add configuration options for conversational agent, including verbosity, reasoning display, and tool iteration limits --- src/cli/handlers/agent/general_commands.cc | 27 ++++++++++ .../agent/conversational_agent_service.cc | 51 +++++++++++++++++-- .../agent/conversational_agent_service.h | 13 +++++ src/cli/service/agent/simple_chat_session.cc | 1 + src/cli/service/agent/simple_chat_session.h | 5 ++ 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/cli/handlers/agent/general_commands.cc b/src/cli/handlers/agent/general_commands.cc index 763787d1..d5121d44 100644 --- a/src/cli/handlers/agent/general_commands.cc +++ b/src/cli/handlers/agent/general_commands.cc @@ -15,6 +15,7 @@ #include "absl/status/statusor.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" +#include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_replace.h" @@ -628,6 +629,10 @@ absl::Status HandleSimpleChatCommand(const std::vector& arg_vec, std::optional batch_file; std::optional single_message; bool non_interactive = false; + bool verbose = false; + bool show_reasoning = true; + int max_tool_iterations = 4; + int max_retry_attempts = 3; for (size_t i = 0; i < arg_vec.size(); ++i) { const std::string& arg = arg_vec[i]; @@ -639,13 +644,35 @@ absl::Status HandleSimpleChatCommand(const std::vector& arg_vec, ++i; } else if (arg == "--non-interactive" || arg == "-n") { non_interactive = true; + } else if (arg == "--verbose" || arg == "-v") { + verbose = true; + } else if (arg == "--no-reasoning") { + show_reasoning = false; + } else if (absl::StartsWith(arg, "--max-tool-iterations=")) { + absl::SimpleAtoi(arg.substr(22), &max_tool_iterations); + } else if (arg == "--max-tool-iterations" && i + 1 < arg_vec.size()) { + absl::SimpleAtoi(arg_vec[i + 1], &max_tool_iterations); + ++i; + } else if (absl::StartsWith(arg, "--max-retries=")) { + absl::SimpleAtoi(arg.substr(14), &max_retry_attempts); + } else if (arg == "--max-retries" && i + 1 < arg_vec.size()) { + absl::SimpleAtoi(arg_vec[i + 1], &max_retry_attempts); + ++i; } else if (!absl::StartsWith(arg, "--") && !single_message.has_value()) { // Treat first non-flag argument as the message single_message = arg; } } + // Configure agent + agent::AgentConfig config; + config.verbose = verbose; + config.show_reasoning = show_reasoning; + config.max_tool_iterations = max_tool_iterations; + config.max_retry_attempts = max_retry_attempts; + SimpleChatSession session; + session.SetConfig(config); session.SetRomContext(&rom); // Priority: batch file > single message > interactive/piped diff --git a/src/cli/service/agent/conversational_agent_service.cc b/src/cli/service/agent/conversational_agent_service.cc index 30a2b456..c28c4c67 100644 --- a/src/cli/service/agent/conversational_agent_service.cc +++ b/src/cli/service/agent/conversational_agent_service.cc @@ -151,6 +151,11 @@ ConversationalAgentService::ConversationalAgentService() { ai_service_ = CreateAIService(); } +ConversationalAgentService::ConversationalAgentService(const AgentConfig& config) + : config_(config) { + ai_service_ = CreateAIService(); +} + void ConversationalAgentService::SetRomContext(Rom* rom) { rom_context_ = rom; tool_dispatcher_.SetRomContext(rom_context_); @@ -174,16 +179,27 @@ absl::StatusOr ConversationalAgentService::SendMessage( history_.push_back(CreateMessage(ChatMessage::Sender::kUser, message)); } - constexpr int kMaxToolIterations = 4; + const int max_iterations = config_.max_tool_iterations; bool waiting_for_text_response = false; - for (int iteration = 0; iteration < kMaxToolIterations; ++iteration) { + if (config_.verbose) { + util::PrintInfo(absl::StrCat("Starting agent loop (max ", max_iterations, " iterations)")); + util::PrintInfo(absl::StrCat("History size: ", history_.size(), " messages")); + } + + for (int iteration = 0; iteration < max_iterations; ++iteration) { + if (config_.verbose) { + util::PrintSeparator(); + std::cout << util::colors::kCyan << "Iteration " << (iteration + 1) + << "/" << max_iterations << util::colors::kReset << std::endl; + } + // Show loading indicator while waiting for AI response util::LoadingIndicator loader( waiting_for_text_response ? "Generating final response..." : "Thinking...", - true); + !config_.verbose); // Hide spinner in verbose mode loader.Start(); auto response_or = ai_service_->GenerateResponse(history_); @@ -198,12 +214,28 @@ absl::StatusOr ConversationalAgentService::SendMessage( const auto& agent_response = response_or.value(); + if (config_.verbose) { + util::PrintInfo("Received agent response:"); + std::cout << util::colors::kDim << " - Tool calls: " + << agent_response.tool_calls.size() << util::colors::kReset << std::endl; + std::cout << util::colors::kDim << " - Commands: " + << agent_response.commands.size() << util::colors::kReset << std::endl; + std::cout << util::colors::kDim << " - Text response: " + << (agent_response.text_response.empty() ? "empty" : "present") + << util::colors::kReset << std::endl; + if (!agent_response.reasoning.empty() && config_.show_reasoning) { + std::cout << util::colors::kYellow << " 💭 Reasoning: " + << util::colors::kDim << agent_response.reasoning + << util::colors::kReset << std::endl; + } + } + if (!agent_response.tool_calls.empty()) { // Check if we were waiting for a text response but got more tool calls instead if (waiting_for_text_response) { util::PrintWarning( absl::StrCat("LLM called tools again instead of providing final response (Iteration: ", - iteration, "/", kMaxToolIterations, ")")); + iteration + 1, "/", max_iterations, ")")); } bool executed_tool = false; @@ -228,6 +260,15 @@ absl::StatusOr ConversationalAgentService::SendMessage( const std::string& tool_output = tool_result_or.value(); if (!tool_output.empty()) { util::PrintSuccess("Tool executed successfully"); + + if (config_.verbose) { + std::cout << util::colors::kDim << "Tool output (truncated):" + << util::colors::kReset << std::endl; + std::string preview = tool_output.substr(0, std::min(size_t(200), tool_output.size())); + if (tool_output.size() > 200) preview += "..."; + std::cout << util::colors::kDim << preview << util::colors::kReset << std::endl; + } + // Add tool result with a clear marker for the LLM std::string marked_output = "[TOOL RESULT] " + tool_output; history_.push_back( @@ -249,7 +290,7 @@ absl::StatusOr ConversationalAgentService::SendMessage( agent_response.commands.empty()) { util::PrintWarning( absl::StrCat("LLM did not provide text_response after receiving tool results (Iteration: ", - iteration, "/", kMaxToolIterations, ")")); + iteration + 1, "/", max_iterations, ")")); // Continue to give it another chance continue; } diff --git a/src/cli/service/agent/conversational_agent_service.h b/src/cli/service/agent/conversational_agent_service.h index a9ea8b35..6f2f2e44 100644 --- a/src/cli/service/agent/conversational_agent_service.h +++ b/src/cli/service/agent/conversational_agent_service.h @@ -29,9 +29,17 @@ struct ChatMessage { std::optional table_data; }; +struct AgentConfig { + int max_tool_iterations = 4; // Maximum number of tool calling iterations + int max_retry_attempts = 3; // Maximum retries on errors + bool verbose = false; // Enable verbose diagnostic output + bool show_reasoning = true; // Show LLM reasoning in output +}; + class ConversationalAgentService { public: ConversationalAgentService(); + explicit ConversationalAgentService(const AgentConfig& config); // Send a message from the user and get the agent's response. absl::StatusOr SendMessage(const std::string& message); @@ -45,11 +53,16 @@ class ConversationalAgentService { // Clear the current conversation history, preserving ROM/tool context. void ResetConversation(); + // Configuration + void SetConfig(const AgentConfig& config) { config_ = config; } + const AgentConfig& GetConfig() const { return config_; } + private: std::vector history_; std::unique_ptr ai_service_; ToolDispatcher tool_dispatcher_; Rom* rom_context_ = nullptr; + AgentConfig config_; }; } // namespace agent diff --git a/src/cli/service/agent/simple_chat_session.cc b/src/cli/service/agent/simple_chat_session.cc index 9bff7fd0..a3c35d6d 100644 --- a/src/cli/service/agent/simple_chat_session.cc +++ b/src/cli/service/agent/simple_chat_session.cc @@ -14,6 +14,7 @@ #include "absl/strings/str_format.h" #include "absl/time/time.h" +#include "cli/util/terminal_colors.h" namespace yaze { namespace cli { diff --git a/src/cli/service/agent/simple_chat_session.h b/src/cli/service/agent/simple_chat_session.h index 4371fb10..ddcafbdc 100644 --- a/src/cli/service/agent/simple_chat_session.h +++ b/src/cli/service/agent/simple_chat_session.h @@ -34,6 +34,11 @@ class SimpleChatSession { // Set ROM context for tool execution void SetRomContext(Rom* rom); + // Set agent configuration + void SetConfig(const AgentConfig& config) { + agent_service_.SetConfig(config); + } + // Send a single message and get response (blocking) absl::Status SendAndWaitForResponse(const std::string& message, std::string* response_out = nullptr);