forgeant docs-test-0
Build LLM-powered agents in C++
Loading...
Searching...
No Matches
agent.hpp
Go to the documentation of this file.
1#ifndef FORGEANT_AGENT_AGENT_HPP
2#define FORGEANT_AGENT_AGENT_HPP
3
4#include <exception>
17#include <memory>
18#include <optional>
19#include <string>
20#include <string_view>
21#include <type_traits>
22#include <utility>
23#include <variant>
24
25namespace forgeant {
26
27class Agent {
28 public:
29 static std::unique_ptr<Agent> create(const std::string& provider, const AgentOptions& options);
30
31 Agent(LlmProvider& provider, AgentOptions options = {});
32
34
35 template <typename T = std::string>
36 AgentResult<T> run(std::string_view prompt, RunOverrides overrides = {}) {
37 Conversation working;
38 apply_system_prompt(working, overrides);
39 working.add(Message(Role::user, std::string(prompt)));
40 return execute<T>(std::move(working), overrides);
41 }
42
43 template <typename T = std::string>
44 AgentResult<T> run(const Conversation& conversation, RunOverrides overrides = {}) {
45 Conversation working = conversation;
46 apply_system_prompt(working, overrides);
47 return execute<T>(std::move(working), overrides);
48 }
49
50 private:
51 std::unique_ptr<HttpClient> owned_http_;
52 std::unique_ptr<LlmProvider> owned_provider_;
53 LlmProvider* provider_;
54 ToolRegistry registry_;
55 AgentOptions options_;
56
57 Agent(std::unique_ptr<HttpClient> http, std::unique_ptr<LlmProvider> provider,
58 AgentOptions options);
59
60 struct LoopResult {
61 Conversation conversation;
62 Usage total_usage;
63 int iterations = 0;
64 std::string finish_reason;
65 };
66
67 LoopResult execute_loop(Conversation working, const RunOverrides& overrides,
68 const std::optional<Json>& output_schema);
69
70 void apply_system_prompt(Conversation& working, const RunOverrides& overrides) const;
71
72 static std::string extract_last_text(const Conversation& conv);
73
74 template <typename T>
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);
84 return result;
85 } else {
86 auto schema = ParamSchema<T>::schema();
87 StructuredConfig cfg;
88 Usage accumulated;
89 int total_iterations = 0;
90 std::string last_finish_reason;
91 std::string last_error;
92
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);
100
101 auto text = extract_last_text(working);
102 try {
103 auto json = Json::parse(text);
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);
110 return result;
111 } catch (const std::exception& e) {
112 last_error = e.what();
113 if (attempt < cfg.max_retries) {
114 working.add(Message(
116 "Your response did not match the required schema: " + last_error +
117 ". Please respond with valid JSON matching the schema."));
118 }
119 }
120 }
121
122 throw AgentRunError(
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));
127 }
128 }
129};
130
131} // namespace forgeant
132
133#endif // FORGEANT_AGENT_AGENT_HPP
Definition agent.hpp:27
static std::unique_ptr< Agent > create(const std::string &provider, const AgentOptions &options)
Agent(LlmProvider &provider, AgentOptions options={})
AgentResult< T > run(const Conversation &conversation, RunOverrides overrides={})
Definition agent.hpp:44
AgentResult< T > run(std::string_view prompt, RunOverrides overrides={})
Definition agent.hpp:36
void add_tool(Tool tool)
Definition conversation.hpp:12
void add(Message message)
Definition conversation.hpp:20
static Json parse(std::string_view input)
Definition provider.hpp:10
Definition agent.hpp:25
Definition options.hpp:23
Definition result.hpp:11
Definition message.hpp:11
Definition run_overrides.hpp:9
Definition tool.hpp:12