feat: Enhance chat command with multiple output formats and improve help documentation
- Updated the chat command to support new output formats: text, markdown, json, and compact. - Modified the agent configuration to include output format settings. - Enhanced the command line interface to handle new format options and provide detailed usage instructions. - Improved the message printing logic in SimpleChatSession to format output based on the selected format. - Added JSON and Markdown formatting for session metrics and messages. - Updated help documentation to reflect changes in command usage and available options.
This commit is contained in:
@@ -30,6 +30,8 @@ struct ParsedGlobals {
|
||||
std::vector<char*> positional;
|
||||
bool show_help = false;
|
||||
bool show_version = false;
|
||||
bool list_commands = false;
|
||||
std::optional<std::string> help_category;
|
||||
std::optional<std::string> error;
|
||||
};
|
||||
|
||||
@@ -54,8 +56,22 @@ ParsedGlobals ParseGlobalFlags(int argc, char* argv[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (absl::StartsWith(token, "--help=")) {
|
||||
std::string category(token.substr(7));
|
||||
if (!category.empty()) {
|
||||
result.help_category = category;
|
||||
} else {
|
||||
result.show_help = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--help" || token == "-h") {
|
||||
result.show_help = true;
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
result.help_category = std::string(argv[++i]);
|
||||
} else {
|
||||
result.show_help = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -69,6 +85,23 @@ ParsedGlobals ParseGlobalFlags(int argc, char* argv[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--list-commands" || token == "--list") {
|
||||
result.list_commands = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (absl::StartsWith(token, "--quiet=")) {
|
||||
std::string value(token.substr(8));
|
||||
bool enable = value.empty() || value == "1" || value == "true";
|
||||
absl::SetFlag(&FLAGS_quiet, enable);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--quiet" || token == "-q") {
|
||||
absl::SetFlag(&FLAGS_quiet, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (absl::StartsWith(token, "--rom=")) {
|
||||
absl::SetFlag(&FLAGS_rom, std::string(token.substr(6)));
|
||||
continue;
|
||||
@@ -200,6 +233,16 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
yaze::cli::ModernCLI cli;
|
||||
|
||||
if (globals.help_category.has_value()) {
|
||||
cli.PrintCategoryHelp(*globals.help_category);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (globals.list_commands) {
|
||||
cli.PrintCommandSummary();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (globals.show_help) {
|
||||
cli.PrintTopLevelHelp();
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -73,7 +73,7 @@ constexpr absl::string_view kUsage =
|
||||
" --ai_model=<name> Model name (e.g., qwen2.5-coder:7b for Ollama)\n"
|
||||
" --ollama_host=<url> Ollama server URL (default: http://localhost:11434)\n"
|
||||
" --gemini_api_key=<key> Gemini API key (or set GEMINI_API_KEY env var)\n"
|
||||
" --format=<type> Output format: json | table | yaml\n"
|
||||
" --format=<type> Output format: text | markdown | json | compact\n"
|
||||
"\n"
|
||||
"For more details, see: docs/simple_chat_input_methods.md";
|
||||
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
#include "absl/flags/declare.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/status/status.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"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "app/core/project.h"
|
||||
#include "app/zelda3/dungeon/room.h"
|
||||
@@ -533,6 +534,7 @@ absl::Status HandleSimpleChatCommand(const std::vector<std::string>& arg_vec,
|
||||
std::optional<std::string> batch_file;
|
||||
std::optional<std::string> single_message;
|
||||
bool verbose = false;
|
||||
std::optional<std::string> format_option;
|
||||
|
||||
for (size_t i = 0; i < arg_vec.size(); ++i) {
|
||||
const std::string& arg = arg_vec[i];
|
||||
@@ -540,6 +542,16 @@ absl::Status HandleSimpleChatCommand(const std::vector<std::string>& arg_vec,
|
||||
batch_file = arg.substr(7);
|
||||
} else if (arg == "--file" && i + 1 < arg_vec.size()) {
|
||||
batch_file = arg_vec[++i];
|
||||
} else if (absl::StartsWith(arg, "--format=")) {
|
||||
format_option = arg.substr(9);
|
||||
} else if (arg == "--format" && i + 1 < arg_vec.size()) {
|
||||
format_option = arg_vec[++i];
|
||||
} else if (arg == "--json") {
|
||||
format_option = "json";
|
||||
} else if (arg == "--markdown" || arg == "--md") {
|
||||
format_option = "markdown";
|
||||
} else if (arg == "--compact" || arg == "--raw") {
|
||||
format_option = "compact";
|
||||
} else if (arg == "--verbose" || arg == "-v") {
|
||||
verbose = true;
|
||||
} else if (!absl::StartsWith(arg, "--") && !single_message.has_value()) {
|
||||
@@ -549,6 +561,23 @@ absl::Status HandleSimpleChatCommand(const std::vector<std::string>& arg_vec,
|
||||
|
||||
agent::AgentConfig config;
|
||||
config.verbose = verbose;
|
||||
if (format_option.has_value()) {
|
||||
std::string normalized = absl::AsciiStrToLower(*format_option);
|
||||
if (normalized == "json") {
|
||||
config.output_format = AgentOutputFormat::kJson;
|
||||
} else if (normalized == "markdown" || normalized == "md") {
|
||||
config.output_format = AgentOutputFormat::kMarkdown;
|
||||
} else if (normalized == "compact" || normalized == "raw") {
|
||||
config.output_format = AgentOutputFormat::kCompact;
|
||||
} else if (normalized == "text" || normalized == "friendly" ||
|
||||
normalized == "pretty") {
|
||||
config.output_format = AgentOutputFormat::kFriendly;
|
||||
} else {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrCat("Unsupported chat format: ", *format_option,
|
||||
". Supported formats: text, markdown, json, compact"));
|
||||
}
|
||||
}
|
||||
|
||||
SimpleChatSession session;
|
||||
session.SetConfig(config);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "cli/modern_cli.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/declare.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
@@ -13,6 +16,7 @@
|
||||
#include "cli/z3ed_ascii_logo.h"
|
||||
|
||||
ABSL_DECLARE_FLAG(std::string, rom);
|
||||
ABSL_DECLARE_FLAG(bool, quiet);
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
@@ -114,6 +118,48 @@ void ModernCLI::SetupCommands() {
|
||||
}
|
||||
};
|
||||
|
||||
commands_["chat"] = {
|
||||
.name = "chat",
|
||||
.description =
|
||||
"Unified chat entrypoint with text, markdown, or JSON output",
|
||||
.usage =
|
||||
"z3ed chat [--mode=simple|gui|test] [--format=text|markdown|json|compact]"
|
||||
" [--prompt \"<message>\"] [--file=<questions.txt>] [--quiet]",
|
||||
.handler = [this](const std::vector<std::string>& args) -> absl::Status {
|
||||
return HandleChatEntryCommand(args);
|
||||
}
|
||||
};
|
||||
|
||||
commands_["proposal"] = {
|
||||
.name = "proposal",
|
||||
.description = "Review and manage AI-generated change proposals",
|
||||
.usage =
|
||||
"z3ed proposal <run|list|diff|show|accept|commit|revert> [options]",
|
||||
.handler = [this](const std::vector<std::string>& args) -> absl::Status {
|
||||
return HandleProposalCommand(args);
|
||||
}
|
||||
};
|
||||
|
||||
commands_["widget"] = {
|
||||
.name = "widget",
|
||||
.description = "Discover GUI widgets exposed through automation APIs",
|
||||
.usage = "z3ed widget discover [--window=<name>] [--type=<widget>]",
|
||||
.handler = [this](const std::vector<std::string>& args) -> absl::Status {
|
||||
return HandleWidgetCommand(args);
|
||||
}
|
||||
};
|
||||
|
||||
commands_["widget discover"] = {
|
||||
.name = "widget discover",
|
||||
.description = "Inspect UI widgets using the automation service",
|
||||
.usage =
|
||||
"z3ed widget discover [--window=<name>] [--type=<widget>]"
|
||||
" [--format=text|json]",
|
||||
.handler = [this](const std::vector<std::string>& args) -> absl::Status {
|
||||
return HandleWidgetCommand(args);
|
||||
}
|
||||
};
|
||||
|
||||
commands_["project build"] = {
|
||||
.name = "project build",
|
||||
.description = "Build the project and create a new ROM file",
|
||||
@@ -305,11 +351,25 @@ void ModernCLI::ShowHelp() {
|
||||
std::cout << "\033[1m\033[36mCOMMANDS:\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " \033[1m🤖 AI Agent\033[0m" << std::endl;
|
||||
std::cout << " agent simple-chat Natural language ROM queries" << std::endl;
|
||||
std::cout << " agent test-conversation Interactive testing mode" << std::endl;
|
||||
std::cout << " \033[90m→ z3ed help agent\033[0m" << std::endl;
|
||||
std::cout << " \033[1m🤖 AI Agent\033[0m" << std::endl;
|
||||
std::cout << " chat Unified chat entrypoint (text/json/markdown)" << std::endl;
|
||||
std::cout << " agent simple-chat Natural language ROM queries" << std::endl;
|
||||
std::cout << " agent test-conversation Interactive testing mode" << std::endl;
|
||||
std::cout << " \033[90m→ z3ed help chat, z3ed help agent\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " \033[1m🧠 Proposals\033[0m" << std::endl;
|
||||
std::cout << " proposal run Execute AI-driven sandbox plan" << std::endl;
|
||||
std::cout << " proposal list Show pending proposals" << std::endl;
|
||||
std::cout << " proposal diff Review latest sandbox diff" << std::endl;
|
||||
std::cout << " proposal accept Apply sandbox changes" << std::endl;
|
||||
std::cout << " \033[90m→ z3ed help proposal\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " \033[1m🪟 GUI Automation\033[0m" << std::endl;
|
||||
std::cout << " widget discover Inspect GUI widgets via automation" << std::endl;
|
||||
std::cout << " \033[90m→ z3ed help widget\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " \033[1m🔧 ROM Patching\033[0m" << std::endl;
|
||||
std::cout << " patch apply-asar Apply Asar 65816 assembly patch" << std::endl;
|
||||
@@ -350,7 +410,7 @@ void ModernCLI::ShowHelp() {
|
||||
|
||||
std::cout << "\033[1m\033[36mQUICK START:\033[0m" << std::endl;
|
||||
std::cout << " z3ed --tui" << std::endl;
|
||||
std::cout << " z3ed agent simple-chat \"What is room 5?\" --rom=zelda3.sfc" << std::endl;
|
||||
std::cout << " z3ed chat \"What is room 5?\" --rom=zelda3.sfc --format=markdown" << std::endl;
|
||||
std::cout << " z3ed patch apply-asar patch.asm --rom=zelda3.sfc" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
@@ -361,6 +421,14 @@ void ModernCLI::PrintTopLevelHelp() const {
|
||||
const_cast<ModernCLI*>(this)->ShowHelp();
|
||||
}
|
||||
|
||||
void ModernCLI::PrintCategoryHelp(const std::string& category) const {
|
||||
const_cast<ModernCLI*>(this)->ShowCategoryHelp(category);
|
||||
}
|
||||
|
||||
void ModernCLI::PrintCommandSummary() const {
|
||||
const_cast<ModernCLI*>(this)->ShowCommandSummary();
|
||||
}
|
||||
|
||||
void ModernCLI::ShowCategoryHelp(const std::string& category) {
|
||||
std::cout << GetColoredLogo() << std::endl;
|
||||
std::cout << std::endl;
|
||||
@@ -395,6 +463,54 @@ void ModernCLI::ShowCategoryHelp(const std::string& category) {
|
||||
std::cout << " • Use --ai_provider=gemini or --ai_provider=ollama" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
} else if (category == "chat") {
|
||||
std::cout << "\033[1m\033[36m💬 CHAT ENTRYPOINT\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mDESCRIPTION:\033[0m" << std::endl;
|
||||
std::cout << " Launch the embedded agent in text, markdown, or JSON-friendly modes." << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mMODES:\033[0m" << std::endl;
|
||||
std::cout << " chat --mode=simple Quick REPL with --format=text|markdown|json|compact" << std::endl;
|
||||
std::cout << " chat --mode=batch --file=F Run prompts from file (one per line)" << std::endl;
|
||||
std::cout << " chat --mode=gui Launch the full FTXUI conversation experience" << std::endl;
|
||||
std::cout << " chat --mode=test Execute scripted agent conversation for QA" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mOPTIONS:\033[0m" << std::endl;
|
||||
std::cout << " --format=text|markdown|json|compact Control response formatting" << std::endl;
|
||||
std::cout << " --prompt \"<msg>\" Send a single message and exit" << std::endl;
|
||||
std::cout << " --file questions.txt Batch mode input" << std::endl;
|
||||
std::cout << " --quiet Suppress extra banners" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
} else if (category == "proposal") {
|
||||
std::cout << "\033[1m\033[36m🧠 PROPOSAL WORKFLOWS\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mCOMMANDS:\033[0m" << std::endl;
|
||||
std::cout << " proposal run --prompt \"<desc>\" Plan and execute changes in sandbox" << std::endl;
|
||||
std::cout << " proposal list Show pending proposals" << std::endl;
|
||||
std::cout << " proposal diff [--proposal-id=X] Inspect latest diff/log" << std::endl;
|
||||
std::cout << " proposal accept --proposal-id=X Apply sandbox changes to main ROM" << std::endl;
|
||||
std::cout << " proposal commit | proposal revert Persist or undo sandbox changes" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mTIPS:\033[0m" << std::endl;
|
||||
std::cout << " • Run `z3ed proposal list` frequently to monitor progress" << std::endl;
|
||||
std::cout << " • Use `--prompt` to describe tasks in natural language" << std::endl;
|
||||
std::cout << " • Sandbox artifacts live alongside proposal logs" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
} else if (category == "widget") {
|
||||
std::cout << "\033[1m\033[36m🪟 GUI WIDGET DISCOVERY\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mCOMMANDS:\033[0m" << std::endl;
|
||||
std::cout << " widget discover [--window=<name>] [--type=<widget>]" << std::endl;
|
||||
std::cout << " Enumerate UI widgets available through automation hooks" << std::endl;
|
||||
std::cout << " Options: --format=table|json, --limit <n>, --include-invisible, --include-disabled" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1mTIPS:\033[0m" << std::endl;
|
||||
std::cout << " • Requires the YAZE GUI to be running locally" << std::endl;
|
||||
std::cout << " • Combine with `z3ed proposal run` for automated UI tests" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
} else if (category == "patch") {
|
||||
std::cout << "\033[1m\033[36m🔧 ROM PATCHING COMMANDS\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
@@ -520,12 +636,44 @@ void ModernCLI::ShowCategoryHelp(const std::string& category) {
|
||||
} else {
|
||||
std::cout << "\033[1m\033[31mUnknown category: " << category << "\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Available categories: agent, patch, rom, overworld, dungeon, gfx, palette" << std::endl;
|
||||
std::cout << "Available categories: agent, chat, proposal, widget, patch, rom, overworld, dungeon, gfx, palette" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Use 'z3ed --help' to see all commands." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ModernCLI::ShowCommandSummary() const {
|
||||
std::cout << GetColoredLogo() << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "\033[1m\033[36mCOMMANDS OVERVIEW\033[0m" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
for (const auto& [key, info] : commands_) {
|
||||
std::string headline = info.description;
|
||||
const size_t newline_pos = headline.find('\n');
|
||||
if (newline_pos != std::string::npos) {
|
||||
headline = headline.substr(0, newline_pos);
|
||||
}
|
||||
if (headline.empty()) {
|
||||
headline = info.usage;
|
||||
}
|
||||
if (headline.size() > 80) {
|
||||
headline = absl::StrCat(headline.substr(0, 77), "…");
|
||||
}
|
||||
|
||||
std::string label = info.name;
|
||||
if (label.size() > 24) {
|
||||
label = absl::StrCat(label.substr(0, 23), "…");
|
||||
}
|
||||
|
||||
std::cout << " "
|
||||
<< absl::StrFormat("%-24s%s", label, headline) << std::endl;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "Use \033[90mz3ed help <topic>\033[0m for detailed information." << std::endl;
|
||||
}
|
||||
|
||||
absl::Status ModernCLI::Run(int argc, char* argv[]) {
|
||||
if (argc < 2) {
|
||||
ShowHelp();
|
||||
@@ -737,8 +885,143 @@ absl::Status ModernCLI::HandleOverworldSetTileCommand(const std::vector<std::str
|
||||
}
|
||||
|
||||
absl::Status ModernCLI::HandleSpriteCreateCommand(const std::vector<std::string>& args) {
|
||||
SpriteCreate handler;
|
||||
return handler.Run(args);
|
||||
SpriteCreate handler;
|
||||
return handler.Run(args);
|
||||
}
|
||||
|
||||
absl::Status ModernCLI::HandleChatEntryCommand(
|
||||
const std::vector<std::string>& args) {
|
||||
std::string mode = "simple";
|
||||
std::optional<std::string> prompt;
|
||||
std::vector<std::string> forwarded;
|
||||
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
const std::string& token = args[i];
|
||||
if (absl::StartsWith(token, "--mode=")) {
|
||||
mode = absl::AsciiStrToLower(token.substr(7));
|
||||
continue;
|
||||
}
|
||||
if (token == "--mode" && i + 1 < args.size()) {
|
||||
mode = absl::AsciiStrToLower(args[i + 1]);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (absl::StartsWith(token, "--prompt=")) {
|
||||
prompt = token.substr(9);
|
||||
continue;
|
||||
}
|
||||
if (token == "--prompt" && i + 1 < args.size()) {
|
||||
prompt = args[i + 1];
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (token == "--quiet" || token == "-q") {
|
||||
absl::SetFlag(&FLAGS_quiet, true);
|
||||
continue;
|
||||
}
|
||||
if (!absl::StartsWith(token, "--") && !prompt.has_value()) {
|
||||
prompt = token;
|
||||
continue;
|
||||
}
|
||||
forwarded.push_back(token);
|
||||
}
|
||||
|
||||
const std::string normalized_mode = absl::AsciiStrToLower(mode);
|
||||
|
||||
auto has_batch_file = [&forwarded]() {
|
||||
for (const auto& token : forwarded) {
|
||||
if (absl::StartsWith(token, "--file") || token == "--file") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
std::vector<std::string> agent_args;
|
||||
if (normalized_mode == "gui" || normalized_mode == "visual" ||
|
||||
normalized_mode == "tui") {
|
||||
if (prompt.has_value()) {
|
||||
return absl::InvalidArgumentError(
|
||||
"GUI chat mode launches the interactive TUI and does not accept a --prompt value.");
|
||||
}
|
||||
agent_args.push_back("chat");
|
||||
} else if (normalized_mode == "test" || normalized_mode == "qa") {
|
||||
if (prompt.has_value()) {
|
||||
return absl::InvalidArgumentError(
|
||||
"Test conversation mode does not accept an inline prompt.");
|
||||
}
|
||||
agent_args.push_back("test-conversation");
|
||||
} else {
|
||||
if (normalized_mode == "batch" && !has_batch_file()) {
|
||||
return absl::InvalidArgumentError(
|
||||
"Batch chat mode requires a --file=<path> option.");
|
||||
}
|
||||
agent_args.push_back("simple-chat");
|
||||
if (prompt.has_value()) {
|
||||
agent_args.push_back(*prompt);
|
||||
}
|
||||
}
|
||||
|
||||
agent_args.insert(agent_args.end(), forwarded.begin(), forwarded.end());
|
||||
return HandleAgentCommand(agent_args);
|
||||
}
|
||||
|
||||
absl::Status ModernCLI::HandleProposalCommand(
|
||||
const std::vector<std::string>& args) {
|
||||
if (args.empty()) {
|
||||
ShowCategoryHelp("proposal");
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::string subcommand = absl::AsciiStrToLower(args[0]);
|
||||
std::vector<std::string> forwarded(args.begin() + 1, args.end());
|
||||
std::vector<std::string> agent_args;
|
||||
|
||||
if (subcommand == "run" || subcommand == "plan") {
|
||||
agent_args.push_back(subcommand);
|
||||
} else if (subcommand == "list") {
|
||||
agent_args.push_back("list");
|
||||
} else if (subcommand == "diff" || subcommand == "show") {
|
||||
agent_args.push_back("diff");
|
||||
} else if (subcommand == "accept") {
|
||||
agent_args.push_back("accept");
|
||||
} else if (subcommand == "commit") {
|
||||
agent_args.push_back("commit");
|
||||
} else if (subcommand == "revert" || subcommand == "reject") {
|
||||
agent_args.push_back("revert");
|
||||
} else if (subcommand == "test") {
|
||||
agent_args.push_back("test");
|
||||
} else {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrCat("Unknown proposal command: ", subcommand,
|
||||
". Valid actions: run, plan, list, diff, show, accept, commit, revert."));
|
||||
}
|
||||
|
||||
agent_args.insert(agent_args.end(), forwarded.begin(), forwarded.end());
|
||||
return HandleAgentCommand(agent_args);
|
||||
}
|
||||
|
||||
absl::Status ModernCLI::HandleWidgetCommand(
|
||||
const std::vector<std::string>& args) {
|
||||
if (args.empty()) {
|
||||
ShowCategoryHelp("widget");
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::vector<std::string> forwarded(args.begin(), args.end());
|
||||
std::string subcommand = absl::AsciiStrToLower(forwarded[0]);
|
||||
std::vector<std::string> agent_args;
|
||||
|
||||
if (subcommand == "discover") {
|
||||
agent_args.push_back("gui");
|
||||
agent_args.insert(agent_args.end(), forwarded.begin(), forwarded.end());
|
||||
} else {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrCat("Unknown widget command: ", forwarded[0],
|
||||
". Try 'z3ed widget discover'."));
|
||||
}
|
||||
|
||||
return HandleAgentCommand(agent_args);
|
||||
}
|
||||
|
||||
} // namespace cli
|
||||
|
||||
@@ -25,6 +25,8 @@ class ModernCLI {
|
||||
absl::Status Run(int argc, char* argv[]);
|
||||
CommandHandler* GetCommandHandler(const std::string& name);
|
||||
void PrintTopLevelHelp() const;
|
||||
void PrintCategoryHelp(const std::string& category) const;
|
||||
void PrintCommandSummary() const;
|
||||
|
||||
std::map<std::string, CommandInfo> commands_;
|
||||
|
||||
@@ -32,6 +34,7 @@ class ModernCLI {
|
||||
void SetupCommands();
|
||||
void ShowHelp();
|
||||
void ShowCategoryHelp(const std::string& category);
|
||||
void ShowCommandSummary() const;
|
||||
|
||||
// Command Handlers
|
||||
absl::Status HandleAsarPatchCommand(const std::vector<std::string>& args);
|
||||
@@ -58,6 +61,9 @@ class ModernCLI {
|
||||
absl::Status HandleOverworldListWarpsCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleOverworldSetTileCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleSpriteCreateCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleChatEntryCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleProposalCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleWidgetCommand(const std::vector<std::string>& args);
|
||||
};
|
||||
|
||||
} // namespace cli
|
||||
|
||||
@@ -41,6 +41,13 @@ struct ChatMessage {
|
||||
std::optional<SessionMetrics> metrics;
|
||||
};
|
||||
|
||||
enum class AgentOutputFormat {
|
||||
kFriendly,
|
||||
kCompact,
|
||||
kMarkdown,
|
||||
kJson
|
||||
};
|
||||
|
||||
struct AgentConfig {
|
||||
int max_tool_iterations = 4; // Maximum number of tool calling iterations
|
||||
int max_retry_attempts = 3; // Maximum retries on errors
|
||||
@@ -48,6 +55,7 @@ struct AgentConfig {
|
||||
bool show_reasoning = true; // Show LLM reasoning in output
|
||||
size_t max_history_messages = 50; // Maximum stored history messages per session
|
||||
bool trim_history = true; // Whether to trim history beyond the limit
|
||||
AgentOutputFormat output_format = AgentOutputFormat::kFriendly;
|
||||
};
|
||||
|
||||
class ConversationalAgentService {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "cli/service/agent/simple_chat_session.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -12,7 +14,9 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "cli/util/terminal_colors.h"
|
||||
|
||||
@@ -26,6 +30,170 @@ void SimpleChatSession::SetRomContext(Rom* rom) {
|
||||
agent_service_.SetRomContext(rom);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string EscapeJsonString(absl::string_view input) {
|
||||
std::string output;
|
||||
output.reserve(input.size());
|
||||
for (char ch : input) {
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
output.append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
output.append("\\\"");
|
||||
break;
|
||||
case '\b':
|
||||
output.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
output.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
output.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
output.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
output.append("\\t");
|
||||
break;
|
||||
default: {
|
||||
unsigned char code = static_cast<unsigned char>(ch);
|
||||
if (code < 0x20) {
|
||||
absl::StrAppendFormat(&output, "\\u%04x",
|
||||
static_cast<unsigned int>(code));
|
||||
} else {
|
||||
output.push_back(ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string QuoteJson(absl::string_view value) {
|
||||
return absl::StrCat("\"", EscapeJsonString(value), "\"");
|
||||
}
|
||||
|
||||
std::string TableToJson(const ChatMessage::TableData& table) {
|
||||
std::vector<std::string> header_entries;
|
||||
header_entries.reserve(table.headers.size());
|
||||
for (const auto& header : table.headers) {
|
||||
header_entries.push_back(QuoteJson(header));
|
||||
}
|
||||
|
||||
std::vector<std::string> row_entries;
|
||||
row_entries.reserve(table.rows.size());
|
||||
for (const auto& row : table.rows) {
|
||||
std::vector<std::string> cell_entries;
|
||||
cell_entries.reserve(row.size());
|
||||
for (const auto& cell : row) {
|
||||
cell_entries.push_back(QuoteJson(cell));
|
||||
}
|
||||
row_entries.push_back(
|
||||
absl::StrCat("[", absl::StrJoin(cell_entries, ","), "]"));
|
||||
}
|
||||
|
||||
return absl::StrCat("{\"headers\":[", absl::StrJoin(header_entries, ","),
|
||||
"],\"rows\":[", absl::StrJoin(row_entries, ","),
|
||||
"]}");
|
||||
}
|
||||
|
||||
std::string MetricsToJson(const ChatMessage::SessionMetrics& metrics) {
|
||||
return absl::StrCat(
|
||||
"{\"turn_index\":", metrics.turn_index, ","
|
||||
"\"total_user_messages\":", metrics.total_user_messages, ","
|
||||
"\"total_agent_messages\":", metrics.total_agent_messages, ","
|
||||
"\"total_tool_calls\":", metrics.total_tool_calls, ","
|
||||
"\"total_commands\":", metrics.total_commands, ","
|
||||
"\"total_proposals\":", metrics.total_proposals, ","
|
||||
"\"total_elapsed_seconds\":", metrics.total_elapsed_seconds, ","
|
||||
"\"average_latency_seconds\":", metrics.average_latency_seconds, "}");
|
||||
}
|
||||
|
||||
std::string MessageToJson(const ChatMessage& msg, bool show_timestamp) {
|
||||
std::string json = "{";
|
||||
absl::StrAppend(&json, "\"sender\":\"",
|
||||
msg.sender == ChatMessage::Sender::kUser ? "user"
|
||||
: "agent",
|
||||
"\"");
|
||||
|
||||
absl::StrAppend(&json, ",\"message\":", QuoteJson(msg.message));
|
||||
|
||||
if (msg.json_pretty.has_value()) {
|
||||
absl::StrAppend(&json, ",\"structured\":",
|
||||
QuoteJson(msg.json_pretty.value()));
|
||||
}
|
||||
|
||||
if (msg.table_data.has_value()) {
|
||||
absl::StrAppend(&json, ",\"table\":", TableToJson(*msg.table_data));
|
||||
}
|
||||
|
||||
if (msg.metrics.has_value()) {
|
||||
absl::StrAppend(&json, ",\"metrics\":",
|
||||
MetricsToJson(*msg.metrics));
|
||||
}
|
||||
|
||||
if (show_timestamp) {
|
||||
std::string timestamp =
|
||||
absl::FormatTime("%Y-%m-%dT%H:%M:%S%z", msg.timestamp,
|
||||
absl::LocalTimeZone());
|
||||
absl::StrAppend(&json, ",\"timestamp\":", QuoteJson(timestamp));
|
||||
}
|
||||
|
||||
absl::StrAppend(&json, "}");
|
||||
return json;
|
||||
}
|
||||
|
||||
void PrintMarkdownTable(const ChatMessage::TableData& table) {
|
||||
if (table.headers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "\n|";
|
||||
for (const auto& header : table.headers) {
|
||||
std::cout << " " << header << " |";
|
||||
}
|
||||
std::cout << "\n|";
|
||||
for (size_t i = 0; i < table.headers.size(); ++i) {
|
||||
std::cout << " --- |";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
for (const auto& row : table.rows) {
|
||||
std::cout << "|";
|
||||
for (size_t i = 0; i < table.headers.size(); ++i) {
|
||||
if (i < row.size()) {
|
||||
std::cout << " " << row[i];
|
||||
}
|
||||
std::cout << " |";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintMarkdownMetrics(const ChatMessage::SessionMetrics& metrics) {
|
||||
std::cout << "\n> _Turn " << metrics.turn_index
|
||||
<< ": users=" << metrics.total_user_messages
|
||||
<< ", agents=" << metrics.total_agent_messages
|
||||
<< ", tool-calls=" << metrics.total_tool_calls
|
||||
<< ", commands=" << metrics.total_commands
|
||||
<< ", proposals=" << metrics.total_proposals
|
||||
<< ", elapsed="
|
||||
<< absl::StrFormat("%.2fs avg %.2fs",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds)
|
||||
<< "_\n";
|
||||
}
|
||||
|
||||
std::string SessionMetricsToJson(const ChatMessage::SessionMetrics& metrics) {
|
||||
return MetricsToJson(metrics);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SimpleChatSession::PrintTable(const ChatMessage::TableData& table) {
|
||||
if (table.headers.empty()) return;
|
||||
|
||||
@@ -62,37 +230,77 @@ void SimpleChatSession::PrintTable(const ChatMessage::TableData& table) {
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleChatSession::PrintMessage(const ChatMessage& msg, bool show_timestamp) {
|
||||
const char* sender = (msg.sender == ChatMessage::Sender::kUser) ? "You" : "Agent";
|
||||
|
||||
if (show_timestamp) {
|
||||
std::string timestamp = absl::FormatTime("%H:%M:%S", msg.timestamp, absl::LocalTimeZone());
|
||||
std::cout << "[" << timestamp << "] ";
|
||||
}
|
||||
|
||||
std::cout << sender << ": ";
|
||||
|
||||
if (msg.table_data.has_value()) {
|
||||
std::cout << "\n";
|
||||
PrintTable(msg.table_data.value());
|
||||
} else if (msg.json_pretty.has_value()) {
|
||||
std::cout << "\n" << msg.json_pretty.value() << "\n";
|
||||
} else {
|
||||
std::cout << msg.message << "\n";
|
||||
}
|
||||
void SimpleChatSession::PrintMessage(const ChatMessage& msg,
|
||||
bool show_timestamp) {
|
||||
switch (config_.output_format) {
|
||||
case AgentOutputFormat::kFriendly: {
|
||||
const char* sender =
|
||||
(msg.sender == ChatMessage::Sender::kUser) ? "You" : "Agent";
|
||||
|
||||
if (msg.metrics.has_value()) {
|
||||
const auto& metrics = msg.metrics.value();
|
||||
std::cout << " 📊 Turn " << metrics.turn_index
|
||||
<< " summary — users: " << metrics.total_user_messages
|
||||
<< ", agents: " << metrics.total_agent_messages
|
||||
<< ", tools: " << metrics.total_tool_calls
|
||||
<< ", commands: " << metrics.total_commands
|
||||
<< ", proposals: " << metrics.total_proposals
|
||||
<< ", elapsed: "
|
||||
<< absl::StrFormat("%.2fs avg %.2fs", metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds)
|
||||
<< "\n";
|
||||
if (show_timestamp) {
|
||||
std::string timestamp = absl::FormatTime(
|
||||
"%H:%M:%S", msg.timestamp, absl::LocalTimeZone());
|
||||
std::cout << "[" << timestamp << "] ";
|
||||
}
|
||||
|
||||
std::cout << sender << ": ";
|
||||
|
||||
if (msg.table_data.has_value()) {
|
||||
std::cout << "\n";
|
||||
PrintTable(msg.table_data.value());
|
||||
} else if (msg.json_pretty.has_value()) {
|
||||
std::cout << "\n" << msg.json_pretty.value() << "\n";
|
||||
} else {
|
||||
std::cout << msg.message << "\n";
|
||||
}
|
||||
|
||||
if (msg.metrics.has_value()) {
|
||||
const auto& metrics = msg.metrics.value();
|
||||
std::cout << " 📊 Turn " << metrics.turn_index
|
||||
<< " summary — users: " << metrics.total_user_messages
|
||||
<< ", agents: " << metrics.total_agent_messages
|
||||
<< ", tools: " << metrics.total_tool_calls
|
||||
<< ", commands: " << metrics.total_commands
|
||||
<< ", proposals: " << metrics.total_proposals
|
||||
<< ", elapsed: "
|
||||
<< absl::StrFormat("%.2fs avg %.2fs",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds)
|
||||
<< "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AgentOutputFormat::kCompact: {
|
||||
if (msg.json_pretty.has_value()) {
|
||||
std::cout << msg.json_pretty.value() << "\n";
|
||||
} else if (msg.table_data.has_value()) {
|
||||
PrintTable(msg.table_data.value());
|
||||
} else {
|
||||
std::cout << msg.message << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AgentOutputFormat::kMarkdown: {
|
||||
std::cout << (msg.sender == ChatMessage::Sender::kUser ? "**You:** "
|
||||
: "**Agent:** ");
|
||||
if (msg.table_data.has_value()) {
|
||||
PrintMarkdownTable(msg.table_data.value());
|
||||
} else if (msg.json_pretty.has_value()) {
|
||||
std::cout << "\n```json\n" << msg.json_pretty.value()
|
||||
<< "\n```\n";
|
||||
} else {
|
||||
std::cout << msg.message << "\n";
|
||||
}
|
||||
|
||||
if (msg.metrics.has_value()) {
|
||||
PrintMarkdownMetrics(*msg.metrics);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AgentOutputFormat::kJson: {
|
||||
std::cout << MessageToJson(msg, show_timestamp) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +324,7 @@ absl::Status SimpleChatSession::RunInteractive() {
|
||||
// Check if stdin is a TTY (interactive) or a pipe/file
|
||||
bool is_interactive = isatty(fileno(stdin));
|
||||
|
||||
if (is_interactive) {
|
||||
if (is_interactive && config_.output_format == AgentOutputFormat::kFriendly) {
|
||||
std::cout << "Z3ED Agent Chat (Simple Mode)\n";
|
||||
std::cout << "Type 'quit' or 'exit' to end the session.\n";
|
||||
std::cout << "Type 'reset' to clear conversation history.\n";
|
||||
@@ -125,14 +333,14 @@ absl::Status SimpleChatSession::RunInteractive() {
|
||||
|
||||
std::string input;
|
||||
while (true) {
|
||||
if (is_interactive) {
|
||||
if (is_interactive && config_.output_format != AgentOutputFormat::kJson) {
|
||||
std::cout << "You: ";
|
||||
std::cout.flush(); // Ensure prompt is displayed before reading
|
||||
}
|
||||
|
||||
if (!std::getline(std::cin, input)) {
|
||||
// EOF reached (piped input exhausted or Ctrl+D)
|
||||
if (is_interactive) {
|
||||
if (is_interactive && config_.output_format != AgentOutputFormat::kJson) {
|
||||
std::cout << "\n";
|
||||
}
|
||||
break;
|
||||
@@ -143,31 +351,68 @@ absl::Status SimpleChatSession::RunInteractive() {
|
||||
|
||||
if (input == "reset") {
|
||||
Reset();
|
||||
std::cout << "Conversation history cleared.\n\n";
|
||||
if (config_.output_format == AgentOutputFormat::kJson) {
|
||||
std::cout << "{\"event\":\"history_cleared\"}" << std::endl;
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << "> Conversation history cleared.\n\n";
|
||||
} else {
|
||||
std::cout << "Conversation history cleared.\n\n";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto result = agent_service_.SendMessage(input);
|
||||
if (!result.ok()) {
|
||||
std::cerr << "Error: " << result.status().message() << "\n\n";
|
||||
if (config_.output_format == AgentOutputFormat::kJson) {
|
||||
std::cout << absl::StrCat(
|
||||
"{\"event\":\"error\",\"message\":",
|
||||
QuoteJson(result.status().message()), "}")
|
||||
<< std::endl;
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << "> **Error:** " << result.status().message() << "\n\n";
|
||||
} else if (config_.output_format == AgentOutputFormat::kCompact) {
|
||||
std::cout << "error: " << result.status().message() << "\n";
|
||||
} else {
|
||||
std::cerr << "Error: " << result.status().message() << "\n\n";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
PrintMessage(result.value(), false);
|
||||
std::cout << "\n";
|
||||
if (config_.output_format != AgentOutputFormat::kJson) {
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
const auto metrics = agent_service_.GetMetrics();
|
||||
std::cout << "Session totals — turns: " << metrics.turn_index
|
||||
<< ", user messages: " << metrics.total_user_messages
|
||||
<< ", agent messages: " << metrics.total_agent_messages
|
||||
<< ", tool calls: " << metrics.total_tool_calls
|
||||
<< ", commands: " << metrics.total_commands
|
||||
<< ", proposals: " << metrics.total_proposals
|
||||
<< ", elapsed: "
|
||||
<< absl::StrFormat("%.2fs avg %.2fs\n\n",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds);
|
||||
if (config_.output_format == AgentOutputFormat::kJson) {
|
||||
std::cout << absl::StrCat("{\"event\":\"session_summary\",\"metrics\":",
|
||||
SessionMetricsToJson(metrics), "}")
|
||||
<< std::endl;
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << "\n> **Session totals** ";
|
||||
std::cout << "turns=" << metrics.turn_index << ", users="
|
||||
<< metrics.total_user_messages << ", agents="
|
||||
<< metrics.total_agent_messages << ", tools="
|
||||
<< metrics.total_tool_calls << ", commands="
|
||||
<< metrics.total_commands << ", proposals="
|
||||
<< metrics.total_proposals << ", elapsed="
|
||||
<< absl::StrFormat("%.2fs avg %.2fs",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds)
|
||||
<< "\n\n";
|
||||
} else {
|
||||
std::cout << "Session totals — turns: " << metrics.turn_index
|
||||
<< ", user messages: " << metrics.total_user_messages
|
||||
<< ", agent messages: " << metrics.total_agent_messages
|
||||
<< ", tool calls: " << metrics.total_tool_calls
|
||||
<< ", commands: " << metrics.total_commands
|
||||
<< ", proposals: " << metrics.total_proposals
|
||||
<< ", elapsed: "
|
||||
<< absl::StrFormat("%.2fs avg %.2fs\n\n",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -179,8 +424,12 @@ absl::Status SimpleChatSession::RunBatch(const std::string& input_file) {
|
||||
absl::StrFormat("Could not open file: %s", input_file));
|
||||
}
|
||||
|
||||
std::cout << "Running batch session from: " << input_file << "\n";
|
||||
std::cout << "----------------------------------------\n\n";
|
||||
if (config_.output_format == AgentOutputFormat::kFriendly) {
|
||||
std::cout << "Running batch session from: " << input_file << "\n";
|
||||
std::cout << "----------------------------------------\n\n";
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << "### Batch session: " << input_file << "\n\n";
|
||||
}
|
||||
|
||||
std::string line;
|
||||
int line_num = 0;
|
||||
@@ -190,29 +439,70 @@ absl::Status SimpleChatSession::RunBatch(const std::string& input_file) {
|
||||
// Skip empty lines and comments
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
std::cout << "Input [" << line_num << "]: " << line << "\n";
|
||||
if (config_.output_format == AgentOutputFormat::kFriendly) {
|
||||
std::cout << "Input [" << line_num << "]: " << line << "\n";
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << "- **Input " << line_num << "**: " << line << "\n";
|
||||
} else if (config_.output_format == AgentOutputFormat::kJson) {
|
||||
std::cout << absl::StrCat(
|
||||
"{\"event\":\"batch_input\",\"index\":",
|
||||
line_num, ",\"prompt\":", QuoteJson(line), "}")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
auto result = agent_service_.SendMessage(line);
|
||||
if (!result.ok()) {
|
||||
std::cerr << "Error: " << result.status().message() << "\n\n";
|
||||
if (config_.output_format == AgentOutputFormat::kJson) {
|
||||
std::cout << absl::StrCat(
|
||||
"{\"event\":\"error\",\"index\":", line_num,
|
||||
",\"message\":",
|
||||
QuoteJson(result.status().message()), "}")
|
||||
<< std::endl;
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << " - ⚠️ " << result.status().message() << "\n";
|
||||
} else if (config_.output_format == AgentOutputFormat::kCompact) {
|
||||
std::cout << "error@" << line_num << ": "
|
||||
<< result.status().message() << "\n";
|
||||
} else {
|
||||
std::cerr << "Error: " << result.status().message() << "\n\n";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
PrintMessage(result.value(), false);
|
||||
std::cout << "\n";
|
||||
if (config_.output_format != AgentOutputFormat::kJson) {
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
const auto metrics = agent_service_.GetMetrics();
|
||||
std::cout << "Batch session totals — turns: " << metrics.turn_index
|
||||
<< ", user messages: " << metrics.total_user_messages
|
||||
<< ", agent messages: " << metrics.total_agent_messages
|
||||
<< ", tool calls: " << metrics.total_tool_calls
|
||||
<< ", commands: " << metrics.total_commands
|
||||
<< ", proposals: " << metrics.total_proposals
|
||||
<< ", elapsed: "
|
||||
<< absl::StrFormat("%.2fs avg %.2fs\n\n",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds);
|
||||
if (config_.output_format == AgentOutputFormat::kJson) {
|
||||
std::cout << absl::StrCat("{\"event\":\"session_summary\",\"metrics\":",
|
||||
SessionMetricsToJson(metrics), "}")
|
||||
<< std::endl;
|
||||
} else if (config_.output_format == AgentOutputFormat::kMarkdown) {
|
||||
std::cout << "\n> **Batch totals** turns=" << metrics.turn_index
|
||||
<< ", users=" << metrics.total_user_messages << ", agents="
|
||||
<< metrics.total_agent_messages << ", tools="
|
||||
<< metrics.total_tool_calls << ", commands="
|
||||
<< metrics.total_commands << ", proposals="
|
||||
<< metrics.total_proposals << ", elapsed="
|
||||
<< absl::StrFormat("%.2fs avg %.2fs",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds)
|
||||
<< "\n\n";
|
||||
} else {
|
||||
std::cout << "Batch session totals — turns: " << metrics.turn_index
|
||||
<< ", user messages: " << metrics.total_user_messages
|
||||
<< ", agent messages: " << metrics.total_agent_messages
|
||||
<< ", tool calls: " << metrics.total_tool_calls
|
||||
<< ", commands: " << metrics.total_commands
|
||||
<< ", proposals: " << metrics.total_proposals
|
||||
<< ", elapsed: "
|
||||
<< absl::StrFormat("%.2fs avg %.2fs\n\n",
|
||||
metrics.total_elapsed_seconds,
|
||||
metrics.average_latency_seconds);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class SimpleChatSession {
|
||||
|
||||
// Set agent configuration
|
||||
void SetConfig(const AgentConfig& config) {
|
||||
config_ = config;
|
||||
agent_service_.SetConfig(config);
|
||||
}
|
||||
|
||||
@@ -65,6 +66,7 @@ class SimpleChatSession {
|
||||
void PrintTable(const ChatMessage::TableData& table);
|
||||
|
||||
ConversationalAgentService agent_service_;
|
||||
AgentConfig config_;
|
||||
};
|
||||
|
||||
} // namespace agent
|
||||
|
||||
Reference in New Issue
Block a user