35 template <
typename T = std::
string>
38 apply_system_prompt(working, overrides);
40 return execute<T>(std::move(working), overrides);
43 template <
typename T = std::
string>
46 apply_system_prompt(working, overrides);
47 return execute<T>(std::move(working), overrides);
51 std::unique_ptr<HttpClient> owned_http_;
52 std::unique_ptr<LlmProvider> owned_provider_;
53 LlmProvider* provider_;
54 ToolRegistry registry_;
55 AgentOptions options_;
57 Agent(std::unique_ptr<HttpClient> http, std::unique_ptr<LlmProvider> provider,
58 AgentOptions options);
61 Conversation conversation;
64 std::string finish_reason;
67 LoopResult execute_loop(Conversation working,
const RunOverrides& overrides,
68 const std::optional<Json>& output_schema);
70 void apply_system_prompt(Conversation& working,
const RunOverrides& overrides)
const;
72 static std::string extract_last_text(
const Conversation& conv);
75 AgentResult<T> execute(Conversation working,
const RunOverrides& overrides) {
76 if constexpr (std::is_same_v<T, std::string>) {
77 auto loop = execute_loop(std::move(working), overrides, std::nullopt);
78 AgentResult<std::string> result;
79 result.output = extract_last_text(loop.conversation);
80 result.total_usage = loop.total_usage;
81 result.iterations = loop.iterations;
82 result.finish_reason = std::move(loop.finish_reason);
83 result.conversation = std::move(loop.conversation);
86 auto schema = ParamSchema<T>::schema();
89 int total_iterations = 0;
90 std::string last_finish_reason;
91 std::string last_error;
93 for (
int attempt = 0; attempt <= cfg.max_retries; ++attempt) {
94 auto loop = execute_loop(std::move(working), overrides, schema);
95 working = std::move(loop.conversation);
96 accumulated.input_tokens += loop.total_usage.input_tokens;
97 accumulated.output_tokens += loop.total_usage.output_tokens;
98 total_iterations += loop.iterations;
99 last_finish_reason = std::move(loop.finish_reason);
101 auto text = extract_last_text(working);
104 AgentResult<T> result;
105 result.output = json.template get<T>();
106 result.conversation = std::move(working);
107 result.total_usage = accumulated;
108 result.iterations = total_iterations;
109 result.finish_reason = std::move(last_finish_reason);
111 }
catch (
const std::exception& e) {
112 last_error = e.what();
113 if (attempt < cfg.max_retries) {
116 "Your response did not match the required schema: " + last_error +
117 ". Please respond with valid JSON matching the schema."));
124 "structured output failed after " + std::to_string(cfg.max_retries + 1) +
125 " attempts: " + last_error,
126 std::move(working), accumulated, total_iterations, std::move(last_finish_reason));