Agents Agents — C++ examples backed by real provider calls. cpp examples examples/short-agents src/examples/cpp/short-agents example Agents

These C++ examples are real runnable files. Edit the source file first; this page is rebuilt from the checked-in example and its metadata header.

C++ Grounded Support Agent

Answers a support question grounded in a handbook that is kept out of the model prompt via contextFields.

C++
#include "axllm/axllm.hpp"
#include "axllm/runtime/quickjs/quickjs_runtime.hpp"
#include <cstdlib>
#include <iostream>

int main() {
  const char* key = std::getenv("OPENAI_API_KEY");
  if (key == nullptr || std::string(key).empty()) key = std::getenv("OPENAI_APIKEY");
  if (key == nullptr || std::string(key).empty()) {
    std::cerr << "Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.\n";
    return 2;
  }
  const char* model = std::getenv("AX_OPENAI_MODEL");
  axllm::OpenAICompatibleClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gpt-5.4-mini" : model},
      {"model_config", axllm::object({{"temperature", 0}})},
  }));

  // The handbook can be arbitrarily large. Listing it in `contextFields` keeps it
  // in the agent's runtime so it never inflates the model prompt -- the agent reads
  // it through code, not through tokens. That is the whole point of an Ax agent
  // over a plain gen() call: the source material stays out of the context window.
  std::string handbook =
      "# Acme Cloud -- Support Handbook\n"
      "\n"
      "## Billing\n"
      "- Invoices are issued on the 1st of each month and are due net-15.\n"
      "- Plan downgrades take effect at the END of the current billing cycle, not immediately.\n"
      "- Refunds are issued to the original payment method within 5 business days.\n"
      "\n"
      "## Access\n"
      "- Seats can be added by any workspace Owner under Settings -> Members.\n"
      "- SSO (SAML) is available on Enterprise; SCIM provisioning is Owner-only.\n"
      "\n"
      "## Incidents\n"
      "- Status and uptime are published at status.acme.example.\n"
      "- Sev-1 incidents page the on-call within 5 minutes; updates post every 30 minutes.\n"
      "\n"
      "## Data\n"
      "- Exports are available in CSV and JSON from Settings -> Data.\n"
      "- Deleted workspaces are recoverable for 30 days, then permanently purged.";

  auto assistant = axllm::agent(
      "question:string, handbook:string -> answer:string, citations:string[] \"Handbook sections the answer relies on\"",
      // Keep the handbook in the runtime, out of the prompt.
      axllm::object({
          {"contextFields", axllm::array({"handbook"})},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  axllm::Value result = assistant.forward(
      client,
      axllm::object({
          {"question", "A customer downgraded their plan today. When does it take effect, and can they get a refund for the current cycle?"},
          {"handbook", handbook},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 12}}));

  std::cout << axllm::stringify(result) << "\n";
}

C++ Incident Triage Agent

Triages a noisy incident report held in contextFields, using a lean contextPolicy to keep the raw log out of the prompt while it reasons.

C++
#include "axllm/axllm.hpp"
#include "axllm/runtime/quickjs/quickjs_runtime.hpp"
#include <cstdlib>
#include <iostream>

int main() {
  const char* key = std::getenv("OPENAI_API_KEY");
  if (key == nullptr || std::string(key).empty()) key = std::getenv("OPENAI_APIKEY");
  if (key == nullptr || std::string(key).empty()) {
    std::cerr << "Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.\n";
    return 2;
  }
  const char* model = std::getenv("AX_OPENAI_MODEL");
  axllm::OpenAICompatibleClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gpt-5.4-mini" : model},
      {"model_config", axllm::object({{"temperature", 0}})},
  }));

  // A raw, noisy incident report. It lives in `contextFields`, so the agent works
  // it inside the runtime; `contextPolicy: lean` keeps the prompt compact by
  // preferring live runtime state and summaries over replaying the raw text.
  std::string report =
      "[2026-03-02 14:01:22Z] INFO  gateway       deploy svc-checkout-edge v812 -> prod (channel: canary 10%)\n"
      "[2026-03-02 14:03:10Z] WARN  checkout-api  p95 latency 1180ms (baseline 240ms) region=eu-west-1\n"
      "[2026-03-02 14:04:55Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise\n"
      "[2026-03-02 14:05:01Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise\n"
      "[2026-03-02 14:05:40Z] WARN  payments-gw   circuit half-open, 3 retries exhausted for order=ord_99214\n"
      "[2026-03-02 14:06:12Z] INFO  gateway       canary widened 10% -> 50% for svc-checkout-edge v812\n"
      "[2026-03-02 14:07:33Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise\n"
      "[2026-03-02 14:08:02Z] ERROR checkout-api  user-visible: \"Payment could not be processed\" shown to 1,284 sessions\n"
      "[2026-03-02 14:09:48Z] WARN  payments-gw   connection pool exhausted (max=64) waiting=210\n"
      "[2026-03-02 14:11:20Z] INFO  on-call       paged: SEV-2 opened (eu-west-1 checkout error rate 38%)\n"
      "[2026-03-02 14:14:05Z] INFO  gateway       rollback svc-checkout-edge v812 -> v811 (channel: prod 100%)\n"
      "[2026-03-02 14:17:41Z] INFO  checkout-api  p95 latency 260ms, error rate 0.4% region=eu-west-1\n"
      "[2026-03-02 14:19:10Z] INFO  on-call       SEV-2 mitigated, monitoring for 30m";

  auto triage = axllm::agent(
      "report:string, question:string -> severity:class \"low, medium, high, critical\", rootCause:string, nextSteps:string[], evidence:string[] \"Quoted log lines that support the assessment\"",
      axllm::object({
          {"contextFields", axllm::array({"report"})},
          {"contextPolicy", axllm::object({{"preset", "lean"}, {"budget", "balanced"}})},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  axllm::Value result = triage.forward(
      client,
      axllm::object({
          {"report", report},
          {"question", "What happened, how bad was it, and what should the on-call do next? Cite the lines you relied on."},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 12}}));

  std::cout << axllm::stringify(result) << "\n";
}

C++ Specialist Planner Agent

A specialist that plans a migration from a long brief held in contextFields, using a checkpointed contextPolicy and a runtime-output cap to stay compact.

C++
#include "axllm/axllm.hpp"
#include "axllm/runtime/quickjs/quickjs_runtime.hpp"
#include <cstdlib>
#include <iostream>

int main() {
  const char* key = std::getenv("OPENAI_API_KEY");
  if (key == nullptr || std::string(key).empty()) key = std::getenv("OPENAI_APIKEY");
  if (key == nullptr || std::string(key).empty()) {
    std::cerr << "Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.\n";
    return 2;
  }
  const char* model = std::getenv("AX_OPENAI_MODEL");
  axllm::OpenAICompatibleClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gpt-5.4-mini" : model},
      {"model_config", axllm::object({{"temperature", 0}})},
  }));

  // A long, messy brief -- exactly the kind of input you do not want replayed into
  // the prompt on every turn. `contextFields` holds it in the runtime, the
  // `checkpointed` policy compacts older turns once the prompt grows, and
  // `maxRuntimeChars` caps how much runtime output is echoed back.
  std::string brief =
      "# Migration brief: monolith -> services (draft, unordered notes)\n"
      "\n"
      "Current: single Rails monolith, Postgres primary + 1 replica, Sidekiq for jobs.\n"
      "Pain: deploys take 40m, one bad migration locks the orders table, on-call burnout.\n"
      "Constraints: no downtime windows > 5m, PCI scope must shrink, team of 6, 2 quarters.\n"
      "Hot paths: checkout (writes orders, payments), search (read-heavy), notifications (async).\n"
      "Known landmines: payments code has no tests; search shares the orders DB; a nightly\n"
      "cron rebuilds the catalog and pins CPU for ~20m; the replica lags up to 90s under load.\n"
      "Org wants: independent deploys for checkout, smaller blast radius, an audit trail.\n"
      "Nice to have: event log for orders, read-model for search, feature flags.\n"
      "Hard no: a big-bang rewrite; introducing Kubernetes this year.";

  auto specialist = axllm::agent(
      "brief:string, goal:string -> plan:string[] \"Ordered, concrete steps\", answer:string, risks:string[]",
      axllm::object({
          {"contextFields", axllm::array({"brief"})},
          {"contextPolicy", axllm::object({{"preset", "checkpointed"}, {"budget", "balanced"}})},
          {"maxRuntimeChars", 3000},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  axllm::Value result = specialist.forward(
      client,
      axllm::object({
          {"brief", brief},
          {"goal", "Propose a safe, incremental 2-quarter plan to split checkout out first, respecting the hard constraints."},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 12}}));

  std::cout << axllm::stringify(result) << "\n";
}

C++ Multi-Model Panel

Fans one question across three providers (OpenAI, Gemini, Anthropic), then judges the candidates and synthesizes a single grounded answer.

C++
#include "axllm/axllm.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

static const char* env_or(const char* primary, const char* fallback) {
  const char* value = std::getenv(primary);
  if (value == nullptr || std::string(value).empty()) value = std::getenv(fallback);
  return value;
}

int main() {
  const char* openai_key = env_or("OPENAI_API_KEY", "OPENAI_APIKEY");
  const char* google_key = env_or("GOOGLE_APIKEY", "GOOGLE_API_KEY");
  const char* anthropic_key = env_or("ANTHROPIC_APIKEY", "ANTHROPIC_API_KEY");
  if (openai_key == nullptr || std::string(openai_key).empty() ||
      google_key == nullptr || std::string(google_key).empty() ||
      anthropic_key == nullptr || std::string(anthropic_key).empty()) {
    std::cerr << "Set OPENAI_APIKEY, GOOGLE_APIKEY, and ANTHROPIC_APIKEY to run this multi-provider panel.\n";
    return 2;
  }

  // A panel of three different providers, each answering the same question
  // independently. Plain ax() composition (no agent runtime): fan out to the
  // panel, judge the candidates, then synthesize one grounded answer.
  axllm::OpenAICompatibleClient openai(axllm::object({
      {"api_key", openai_key},
      {"model", "gpt-5.4-mini"},
      {"model_config", axllm::object({{"temperature", 0}})},
  }));
  axllm::GoogleGeminiClient gemini(axllm::object({
      {"api_key", google_key},
      {"model", "gemini-3.5-flash"},
  }));
  axllm::AnthropicClient anthropic(axllm::object({
      {"api_key", anthropic_key},
      {"model", "claude-haiku-4-5"},
  }));

  std::vector<std::pair<std::string, axllm::AIClient*>> panel = {
      {"openai/gpt-5.4-mini", &openai},
      {"google/gemini-3.5-flash", &gemini},
      {"anthropic/claude-haiku-4.5", &anthropic},
  };

  auto researcher = axllm::ax("question:string -> answer:string, keyFindings:string[], citations:string[], confidence:number");
  researcher.set_instruction("Answer independently. Use evidence. Call out uncertainty. Do not optimize for consensus.");

  auto judge = axllm::ax("question:string, candidates:json -> consensus:string[], contradictions:string[], uniqueInsights:string[], blindSpots:string[]");
  judge.set_instruction("Compare the candidates. Find agreement, conflicts, missing coverage, and unique useful points.");

  auto synthesizer = axllm::ax("question:string, candidates:json, review:json -> answer:string, citations:string[], caveats:string[]");
  synthesizer.set_instruction("Write one final answer grounded in the candidates and review. Resolve conflicts explicitly.");

  std::string question = "What are the strongest arguments for and against a national carbon tax?";

  // Each panelist is a different provider answering independently.
  axllm::Value candidates = axllm::Value::array();
  for (const auto& member : panel) {
    axllm::Value response = researcher.forward(*member.second, axllm::object({{"question", question}}));
    axllm::Value candidate = axllm::Core::map_merge(axllm::object({{"model", member.first}}), response);
    axllm::Core::append(candidates, candidate);
  }

  // The judge + synthesizer run on one of the panel clients (OpenAI here).
  axllm::AIClient& orchestrator = openai;
  axllm::Value review = judge.forward(orchestrator, axllm::object({{"question", question}, {"candidates", candidates}}));
  axllm::Value final = synthesizer.forward(
      orchestrator,
      axllm::object({{"question", question}, {"candidates", candidates}, {"review", review}}));

  std::cout << axllm::stringify(final) << "\n";
}
Docs