Refactor Client::chat to return Message instead of ChatResponse

- Changed Client::chat return type from ChatResponse to Message
- Updated OllamaClient and DebugClient to extract message from response
- Simplified Harness to work directly with Message
- ChatResponse is still parsed internally for Usage info logging
This commit is contained in:
2026-06-03 16:05:31 -05:00
parent 2b2829dba7
commit 2f0a2cb089
6 changed files with 21 additions and 21 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
class Client {
public:
virtual ~Client() = default;
virtual std::expected<ChatResponse, std::string> chat(const std::vector<Message>& messages,
virtual std::expected<Message, std::string> chat(const std::vector<Message>& messages,
const std::vector<Tool>& tools) const = 0;
virtual std::expected<std::vector<std::string>, std::string> list_models() const = 0;
};
+1 -1
View File
@@ -6,7 +6,7 @@
class DebugClient : public Client {
public:
std::expected<ChatResponse, std::string> chat(const std::vector<Message>& messages,
std::expected<Message, std::string> chat(const std::vector<Message>& messages,
const std::vector<Tool>& tools) const override;
std::expected<std::vector<std::string>, std::string> list_models() const override;
+1 -1
View File
@@ -17,7 +17,7 @@ public:
explicit OllamaClient(OllamaConfig config = {});
~OllamaClient() override;
std::expected<ChatResponse, std::string> chat(const std::vector<Message>& messages,
std::expected<Message, std::string> chat(const std::vector<Message>& messages,
const std::vector<Tool>& tools) const override;
std::expected<std::vector<std::string>, std::string> list_models() const override;
+5 -2
View File
@@ -2,7 +2,7 @@
#include <iostream>
#include <expected>
std::expected<ChatResponse, std::string> DebugClient::chat(const std::vector<Message>& /* messages */,
std::expected<Message, std::string> DebugClient::chat(const std::vector<Message>& /* messages */,
const std::vector<Tool>& /* tools */) const {
std::string input;
// Read the JSON blob from stdin.
@@ -20,7 +20,10 @@ std::expected<ChatResponse, std::string> DebugClient::chat(const std::vector<Mes
if (!result) {
return std::unexpected(std::string("DebugClient invalid JSON input: ") + result.error());
}
return result.value();
if (result.value().choices.empty())
return std::unexpected(std::string("0 choices in return"));
return result.value().choices[0].message;
}
std::expected<std::vector<std::string>, std::string> DebugClient::list_models() const {
+7 -14
View File
@@ -47,7 +47,7 @@ std::expected<std::string, std::string> Harness::chat(const std::string& user_me
push_message(message);
for (size_t i = 0; i < config_.max_tool_iterations; ++i) {
ChatResponse response;
Message response;
bool done = false;
size_t retries = 20;
while (!done)
@@ -65,21 +65,16 @@ std::expected<std::string, std::string> Harness::chat(const std::string& user_me
done = true;
}
}
auto& choice = response.choices[0];
auto message = choice.message;
std::string finish = choice.finish_reason.empty() ? "stop" : choice.finish_reason;
push_message(message);
push_message(response);
if (finish == "stop") {
if (!message.content.empty())
return message.content;
if (response.content.empty() && response.tool_calls.empty()) {
return "";
}
if (finish == "tool_calls") {
if (!response.tool_calls.empty()) {
std::string prefix = std::string(config_.depth, '>') + (config_.depth ? " " : "");
for (const auto& tc : message.tool_calls) {
for (const auto& tc : response.tool_calls) {
std::string tool_name = tc.function.name;
std::string args_str = tc.function.arguments;
@@ -108,10 +103,8 @@ std::expected<std::string, std::string> Harness::chat(const std::string& user_me
continue;
}
// Unexpected finish_reason — return whatever content we have
if (!message.content.empty())
return message.content;
return "[no content]";
// No tool calls — return content
return response.content;
}
return std::unexpected("max tool iterations exceeded");
+6 -2
View File
@@ -87,7 +87,7 @@ nlohmann::json OllamaClient::build_body(const std::vector<Message>& messages,
return body;
}
std::expected<ChatResponse, std::string> OllamaClient::chat(const std::vector<Message>& messages,
std::expected<Message, std::string> OllamaClient::chat(const std::vector<Message>& messages,
const std::vector<Tool>& tools) const {
nlohmann::json body = build_body(messages, tools);
std::string body_str = body.dump();
@@ -111,7 +111,11 @@ std::expected<ChatResponse, std::string> OllamaClient::chat(const std::vector<Me
std::cerr << "Total Tokens: " << ret.usage.total_tokens << std::endl;
std::cerr << "Input Tokens: " << ret.usage.prompt_tokens << std::endl;
std::cerr << "Generated Tokens: " << ret.usage.completion_tokens << std::endl;
return ret;
if (ret.choices.empty())
return std::unexpected(std::string("No choices returned"));
return ret.choices[0].message;
}
std::expected<std::vector<std::string>, std::string> OllamaClient::list_models() const {