Long-Horizon Agents Long-Horizon Agents — C++ examples backed by real provider calls. cpp examples examples/long-agents src/examples/cpp/long-agents example Long-Horizon 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++ Incident Log Forensics (RLM)

Infers service architecture and root-cause findings from a huge CloudWatch export that never enters the prompt – held in contextFields and worked through the runtime under a lean contextPolicy.

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

// ---------------------------------------------------------------------------
// Synthetic CloudWatch-style export -- generated large on purpose. Dumping these
// raw events into a prompt would blow the context window. The agent keeps them
// in its runtime (contextFields) and only the *evidence it extracts* ever
// reaches the model. Deterministic so the example is reproducible.
// ---------------------------------------------------------------------------
static std::vector<axllm::Value> build_log_dump() {
  std::time_t start = 1772456400;  // 2026-03-02T13:00:00Z
  std::vector<axllm::Value> events;

  auto push = [&](int i, axllm::Value event) {
    std::time_t ts = start + static_cast<std::time_t>(i) * 2;
    std::tm tm_utc{};
    gmtime_r(&ts, &tm_utc);
    char buffer[32];
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &tm_utc);
    axllm::Core::set(event, "timestamp", std::string(buffer));
    axllm::Core::set(event, "requestId", "req-" + std::to_string(100000 + i));
    events.push_back(event);
  };

  for (int i = 0; i < 1600; ++i) {
    // Routine, healthy traffic across the fleet.
    push(i, axllm::object({{"level", "INFO"}, {"service", "gateway"}, {"statusCode", 200}, {"latencyMs", 40 + (i % 30)}, {"message", "route ok GET /checkout"}}));
    push(i, axllm::object({{"level", "INFO"}, {"service", "search-api"}, {"statusCode", 200}, {"latencyMs", 70 + (i % 50)}, {"message", "query ok q=shoes"}}));

    // Window A: payments-gw upstream timeouts spill into checkout-api 502s for
    // enterprise tenants, with retry storms + pool exhaustion.
    if (i >= 300 && i < 520) {
      push(i, axllm::object({{"level", "ERROR"}, {"service", "payments-gw"}, {"statusCode", 504}, {"latencyMs", 10000}, {"tenantTier", "enterprise"}, {"message", "upstream timeout calling acquirer (10s)"}}));
      push(i, axllm::object({{"level", "ERROR"}, {"service", "checkout-api"}, {"statusCode", 502}, {"tenantTier", "enterprise"}, {"message", "bad gateway from svc-payments-gw"}}));
      if (i % 3 == 0) {
        push(i, axllm::object({{"level", "WARN"}, {"service", "payments-gw"}, {"message", "connection pool exhausted (max=64) waiting=200+"}}));
        push(i, axllm::object({{"level", "WARN"}, {"service", "checkout-api"}, {"tenantTier", "enterprise"}, {"message", "user-visible: \"Payment could not be processed\""}}));
      }
    }

    // Window B: the nightly catalog-cron pins CPU and search-api returns 429s.
    if (i >= 1000 && i < 1120) {
      push(i, axllm::object({{"level", "WARN"}, {"service", "catalog-cron"}, {"latencyMs", 0}, {"message", "rebuild step pinning CPU at 95% on shared node"}}));
      push(i, axllm::object({{"level", "ERROR"}, {"service", "search-api"}, {"statusCode", 429}, {"message", "rate limited: downstream catalog unavailable"}}));
    }
  }

  return events;
}

int main() {
  const char* key = std::getenv("GOOGLE_APIKEY");
  if (key == nullptr || std::string(key).empty()) {
    std::cerr << "Set GOOGLE_APIKEY to run this example.\n";
    return 2;
  }
  const char* model = std::getenv("AX_GEMINI_MODEL");
  axllm::GoogleGeminiClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gemini-3.5-flash" : model},
  }));

  std::vector<axllm::Value> log_events = build_log_dump();
  axllm::Value logs = axllm::Value::array();
  for (const auto& event : log_events) axllm::Core::append(logs, event);
  std::cout << "Generated " << log_events.size() << " log events (kept out of the prompt).\n";

  auto log_rlm = axllm::agent(
      "task:string, logs:json \"Raw CloudWatch export; keep this out of the prompt\" -> architecture:string[] \"Services and how they call each other\", findings:json[] \"Each: issue, count, window, evidence, impact\", overallHealth:string, nextActions:string[]",
      axllm::object({
          // The export stays in the runtime; only extracted evidence reaches the model.
          {"contextFields", axllm::array({"logs"})},
          {"contextPolicy", axllm::object({{"preset", "lean"}, {"budget", "balanced"}})},
          {"maxRuntimeChars", 12000},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  axllm::Value report = log_rlm.forward(
      client,
      axllm::object({
          {"logs", logs},
          {"task", "Infer the service architecture from the logs alone. Then find repeated errors, throttles, retries, and bad user states -- with the affected time window, an occurrence count, and concrete log evidence for each."},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 40}}));

  std::cout << "\n=== Report ===\n";
  std::cout << axllm::stringify(report) << "\n";
  std::cout << "\n=== Usage ===\n";
  std::cout << axllm::stringify(log_rlm.get_usage()) << "\n";
}

C++ Codebase Q&A with a Peek Context Map

Answers several dependency questions over one large module index by building and reusing an evolving context map (the “peek” orientation cache), so later questions skip re-scanning the corpus.

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

struct Module {
  std::string path;
  std::vector<std::string> imports;
  std::string writes;
};

// ---------------------------------------------------------------------------
// A large module-dependency index for a monorepo. Each block is a record the
// agent must *search* to answer -- the answers cannot be guessed, only computed
// by filtering the index. Generated large so it would not fit comfortably in a
// prompt; it lives in contextFields and is queried from the runtime.
// ---------------------------------------------------------------------------
static std::vector<Module> build_module_index() {
  std::vector<Module> modules = {
      {"packages/api/middleware/auth.ts", {"packages/shared"}, "-"},
      {"packages/api/middleware/rateLimit.ts", {"packages/db"}, "-"},
      {"packages/api/routes/checkout.ts", {"packages/api/middleware/auth.ts", "packages/services/orders/createOrder.ts", "packages/services/payments/charge.ts"}, "-"},
      {"packages/api/routes/search.ts", {"packages/api/middleware/auth.ts", "packages/services/catalog/searchCatalog.ts"}, "-"},
      {"packages/services/orders/createOrder.ts", {"packages/db", "packages/clients/bus"}, "orders"},
      {"packages/services/orders/orderRepo.ts", {"packages/db"}, "orders"},
      {"packages/services/payments/charge.ts", {"packages/clients/acquirer", "packages/db"}, "payments"},
      {"packages/services/payments/refund.ts", {"packages/clients/acquirer", "packages/db"}, "refunds"},
      {"packages/services/catalog/searchCatalog.ts", {"packages/db"}, "-"},
      {"packages/clients/acquirer/index.ts", {"packages/shared"}, "-"},
      {"packages/clients/bus/index.ts", {"packages/shared"}, "-"},
  };
  // Filler modules so the index is genuinely large; some also depend on the acquirer.
  for (int i = 0; i < 110; ++i) {
    Module m;
    m.path = "packages/services/feature" + std::to_string(i) + "/handler.ts";
    m.imports = {i % 4 == 0 ? "packages/clients/acquirer" : "packages/db", "packages/shared"};
    m.writes = i % 6 == 0 ? "audit" : "-";
    modules.push_back(m);
  }
  return modules;
}

int main() {
  const char* key = std::getenv("GOOGLE_APIKEY");
  if (key == nullptr || std::string(key).empty()) {
    std::cerr << "Set GOOGLE_APIKEY to run this example.\n";
    return 2;
  }
  const char* model = std::getenv("AX_GEMINI_MODEL");
  axllm::GoogleGeminiClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gemini-3.5-flash" : model},
  }));

  std::vector<Module> modules = build_module_index();
  std::string codebase_index;
  for (std::size_t idx = 0; idx < modules.size(); ++idx) {
    const Module& m = modules[idx];
    std::string imports;
    for (std::size_t j = 0; j < m.imports.size(); ++j) {
      if (j > 0) imports += ", ";
      imports += m.imports[j];
    }
    if (idx > 0) codebase_index += "\n\n";
    codebase_index += "PATH: " + m.path + "\nIMPORTS: " + imports + "\nWRITES: " + m.writes;
  }
  std::cout << "Module index: " << modules.size() << " records (kept out of the prompt).\n";

  auto analyst = axllm::agent(
      "context:string, question:string -> answer:string, paths:string[] \"Exact PATH values from the index that answer the question\"",
      axllm::object({
          {"contextFields", axllm::array({"context"})},
          {"contextPolicy", axllm::object({{"preset", "adaptive"}, {"budget", "balanced"}})},
          {"contextOptions", axllm::object({
              {"description", "The context is a module index of \"PATH / IMPORTS / WRITES\" records. Answer by filtering those records in code -- never guess. Return exact PATH values verbatim."},
          })},
          // The Peek context map: small, persistent orientation reused across queries.
          {"contextMap", axllm::object({{"maxChars", 1800}, {"infiniteEvolve", false}, {"evolveSteps", 1}})},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  std::vector<std::string> questions = {
      "Which modules import 'packages/clients/acquirer'? Give the exact PATH values.",
      "Which modules write to the 'orders' table?",
      "What are the direct IMPORTS of packages/api/routes/checkout.ts?",
  };

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  for (const std::string& question : questions) {
    axllm::Value output = analyst.forward(
        client,
        axllm::object({{"context", codebase_index}, {"question", question}}),
        axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 24}}));

    axllm::Value paths = axllm::Core::get(output, "paths", axllm::Value::array());
    std::string paths_text;
    for (const auto& p : axllm::Core::iter(paths)) {
      if (!paths_text.empty()) paths_text += ", ";
      paths_text += axllm::display(p);
    }
    std::cout << "\nQ: " << question << "\n";
    std::cout << "A: " << axllm::display(axllm::Core::get(output, "answer", "")) << "\n";
    std::cout << "Paths: " << paths_text << "\n";
  }

  std::cout << "\nThe context map evolved on the first query and was reused for the rest.\n";
}

C++ Data Analyst (Large Context + Tools)

Combines a large data dictionary held in contextFields with typed warehouse tools, so the agent answers business questions over a big dataset it never has to inline.

C++
#include "axllm/axllm.hpp"
#include "axllm/runtime/quickjs/quickjs_runtime.hpp"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

// ---------------------------------------------------------------------------
// The "warehouse": a few hundred rows that live in the host process and are
// reachable only through tools. The model never sees the rows -- it queries
// them. Deterministic so the example is reproducible.
// ---------------------------------------------------------------------------
static const std::vector<std::string> MONTHS = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

struct Row {
  std::string region;
  std::string product;
  int monthIndex;
  std::string month;
  long units;
  long revenue;
  double returnRate;
};

static std::vector<Row> build_warehouse() {
  const std::vector<std::string> regions = {"North", "South", "East", "West", "Central", "NW", "NE", "SE"};
  const std::vector<std::string> products = {"Widget-A", "Widget-B", "Gadget-X", "Gadget-Y"};
  std::vector<Row> rows;
  std::int64_t seed = 7;

  auto rand = [&]() {
    seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
    return static_cast<double>(seed) / static_cast<double>(0x7FFFFFFF);
  };

  for (const auto& region : regions) {
    for (const auto& product : products) {
      int trend = (product == "Gadget-X" && region == "East") ? 90 : 25;  // a planted winner
      for (int m = 0; m < static_cast<int>(MONTHS.size()); ++m) {
        long units = std::llround(400 + rand() * 1200 + m * trend);
        int price = product.rfind("Gadget", 0) == 0 ? 60 : 38;
        double raw_return = 0.01 + rand() * 0.05 + (product == "Widget-B" ? 0.03 : 0.0);
        double return_rate = std::round(raw_return * 1000.0) / 1000.0;
        rows.push_back(Row{region, product, m, MONTHS[m], units, units * price, return_rate});
      }
    }
  }
  return rows;
}

int main() {
  const char* key = std::getenv("GOOGLE_APIKEY");
  if (key == nullptr || std::string(key).empty()) {
    std::cerr << "Set GOOGLE_APIKEY to run this example.\n";
    return 2;
  }
  const char* model = std::getenv("AX_GEMINI_MODEL");
  axllm::GoogleGeminiClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gemini-3.5-flash" : model},
  }));

  std::vector<Row> warehouse = build_warehouse();
  std::cout << "Warehouse: " << warehouse.size() << " rows (kept out of the prompt).\n";

  // The schema/data dictionary is large-ish and goes into contextFields so the
  // agent orients on column meaning + business rules without the doc entering the prompt.
  std::string schema =
      "TABLE sales (one row per region x product x month)\n"
      "\n"
      "COLUMNS\n"
      "  region       text   one of: North, South, East, West, Central, NW, NE, SE\n"
      "  product      text   one of: Widget-A, Widget-B, Gadget-X, Gadget-Y\n"
      "  month        text   Jan..Dec (calendar order; monthIndex 0..11)\n"
      "  units        int    units sold that month\n"
      "  revenue      int    integer dollars (units * unit price; Gadgets cost more)\n"
      "  returnRate   float  fraction of units returned, 0..1\n"
      "\n"
      "BUSINESS RULES\n"
      "  - \"Growth\" = change in monthly revenue from Jan to Dec for a region+product.\n"
      "  - A return rate above 0.05 (5%) is flagged for quality review.\n"
      "  - Compare like-for-like: always group by region AND product, not either alone.\n"
      "\n"
      "TOOLS AVAILABLE (call them, never invent figures)\n"
      "  query  filter + aggregate a slice -> {matched, totalUnits, totalRevenue, avgReturnRate}\n"
      "  top    rank a metric (\"revenue\"|\"units\") grouped by \"product\"|\"region\" -> [{key, value}]\n"
      "  trend  monthly revenue series (Jan..Dec) for one region + product";

  // --- Host tool handlers over the warehouse (the model never sees the rows) ---
  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  runtime
      .register_callable("query", [&warehouse](axllm::Value p) -> axllm::Value {
        std::string region = axllm::display(axllm::Core::get(p, "region", ""));
        std::string product = axllm::display(axllm::Core::get(p, "product", ""));
        std::string month = axllm::display(axllm::Core::get(p, "month", ""));
        long matched = 0, total_units = 0, total_revenue = 0;
        double sum_return = 0.0;
        for (const auto& r : warehouse) {
          if (!region.empty() && r.region != region) continue;
          if (!product.empty() && r.product != product) continue;
          if (!month.empty() && r.month != month) continue;
          ++matched;
          total_units += r.units;
          total_revenue += r.revenue;
          sum_return += r.returnRate;
        }
        double avg_return = matched > 0 ? std::round((sum_return / matched) * 10000.0) / 10000.0 : 0.0;
        return axllm::object({
            {"matched", static_cast<double>(matched)},
            {"totalUnits", static_cast<double>(total_units)},
            {"totalRevenue", static_cast<double>(total_revenue)},
            {"avgReturnRate", avg_return},
        });
      })
      .register_callable("top", [&warehouse](axllm::Value p) -> axllm::Value {
        std::string metric = axllm::display(axllm::Core::get(p, "metric", "revenue"));
        std::string group_by = axllm::display(axllm::Core::get(p, "groupBy", "product"));
        double limit_raw = 5;
        axllm::Value limit_val = axllm::Core::get(p, "limit", axllm::Value());
        if (limit_val.is_number()) limit_raw = std::stod(axllm::display(limit_val));
        std::size_t limit = limit_raw > 0 ? static_cast<std::size_t>(limit_raw) : 5;

        std::vector<std::pair<std::string, long>> totals;
        auto bump = [&](const std::string& key, long value) {
          for (auto& entry : totals) {
            if (entry.first == key) {
              entry.second += value;
              return;
            }
          }
          totals.push_back({key, value});
        };
        for (const auto& r : warehouse) {
          std::string key = group_by == "region" ? r.region : r.product;
          bump(key, metric == "units" ? r.units : r.revenue);
        }
        std::sort(totals.begin(), totals.end(),
                  [](const auto& a, const auto& b) { return a.second > b.second; });
        axllm::Value ranked = axllm::Value::array();
        for (std::size_t i = 0; i < totals.size() && i < limit; ++i) {
          axllm::Core::append(ranked, axllm::object({
                                          {"key", totals[i].first},
                                          {"value", static_cast<double>(totals[i].second)},
                                      }));
        }
        return ranked;
      })
      .register_callable("trend", [&warehouse](axllm::Value p) -> axllm::Value {
        std::string region = axllm::display(axllm::Core::get(p, "region", ""));
        std::string product = axllm::display(axllm::Core::get(p, "product", ""));
        std::vector<long> series(12, 0);
        for (const auto& r : warehouse) {
          if (r.region == region && r.product == product) series[r.monthIndex] = r.revenue;
        }
        axllm::Value out = axllm::Value::array();
        for (long v : series) axllm::Core::append(out, static_cast<double>(v));
        return out;
      });

  auto analyst = axllm::agent(
      "schema:string, question:string -> answer:string, evidence:string[] \"Concrete figures the answer is based on\"",
      axllm::object({
          // Big data dictionary stays out of the prompt.
          {"contextFields", axllm::array({"schema"})},
          // Tool specs advertised to the model; handlers are registered on the runtime above.
          {"functions", axllm::array({
              axllm::object({
                  {"name", "query"},
                  {"description", "Filter the sales table and return aggregates for the matching rows."},
                  {"parameters", axllm::object({
                      {"type", "object"},
                      {"properties", axllm::object({
                          {"region", axllm::object({{"type", "string"}})},
                          {"product", axllm::object({{"type", "string"}})},
                          {"month", axllm::object({{"type", "string"}})},
                      })},
                  })},
              }),
              axllm::object({
                  {"name", "top"},
                  {"description", "Rank a metric (revenue|units) grouped by product|region, highest first."},
                  {"parameters", axllm::object({
                      {"type", "object"},
                      {"properties", axllm::object({
                          {"metric", axllm::object({{"type", "string"}})},
                          {"groupBy", axllm::object({{"type", "string"}})},
                          {"limit", axllm::object({{"type", "number"}})},
                      })},
                      {"required", axllm::array({"metric", "groupBy"})},
                  })},
              }),
              axllm::object({
                  {"name", "trend"},
                  {"description", "Monthly revenue series (Jan..Dec) for one region and product."},
                  {"parameters", axllm::object({
                      {"type", "object"},
                      {"properties", axllm::object({
                          {"region", axllm::object({{"type", "string"}})},
                          {"product", axllm::object({{"type", "string"}})},
                      })},
                      {"required", axllm::array({"region", "product"})},
                  })},
              }),
          })},
          {"contextPolicy", axllm::object({{"preset", "lean"}, {"budget", "balanced"}})},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::Value result = analyst.forward(
      client,
      axllm::object({
          {"schema", schema},
          {"question", "Which region+product had the strongest Jan->Dec revenue growth, and which products have an average return rate above the 5% review threshold?"},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 40}}));

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

C++ Self-Improving Lab Agent

A many-tool agent that runs experiments, grades them against a rubric with an independent verifier, and distills verified rules into memory – iterating until the rubric passes.

C++
#include "axllm/axllm.hpp"
#include "axllm/runtime/quickjs/quickjs_runtime.hpp"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <string>
#include <vector>

// ---------------------------------------------------------------------------
// The "lab": a deterministic black-box experiment. It scores an ETL config plan
// against a hidden ideal and returns, for any failing check, the exact fix --
// so the agent can converge by following the feedback, not by being told.
// ---------------------------------------------------------------------------
static const std::vector<std::string> CHECKS = {
    "no-nulls", "no-duplicates", "numeric-types", "trimmed-strings", "outliers-handled"};

static std::string remedy_for(const std::string& check) {
  if (check == "no-nulls") return "set nullPolicy=impute (or nullPolicy=drop)";
  if (check == "no-duplicates") return "set dedup=on";
  if (check == "numeric-types") return "set coerceTypes=on";
  if (check == "trimmed-strings") return "set trim=on";
  if (check == "outliers-handled") return "set outlier=clip (or outlier=winsorize)";
  return "";
}

static std::string to_lower(std::string s) {
  std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
  return s;
}

static axllm::Value run_in_sandbox(const std::string& plan) {
  std::string lowered = to_lower(plan);
  std::map<std::string, std::string> flags;
  std::regex re("([a-z]+)\\s*=\\s*([a-z0-9]+)");
  for (std::sregex_iterator it(lowered.begin(), lowered.end(), re), end; it != end; ++it) {
    flags[(*it)[1].str()] = (*it)[2].str();
  }
  auto flag = [&](const std::string& key) -> std::string {
    auto found = flags.find(key);
    return found == flags.end() ? "" : found->second;
  };

  std::map<std::string, bool> ok = {
      {"no-nulls", flag("nullpolicy") == "impute" || flag("nullpolicy") == "drop"},
      {"no-duplicates", flag("dedup") == "on"},
      {"numeric-types", flag("coercetypes") == "on"},
      {"trimmed-strings", flag("trim") == "on"},
      {"outliers-handled", flag("outlier") == "clip" || flag("outlier") == "winsorize"},
  };

  axllm::Value passed = axllm::Value::array();
  axllm::Value failed = axllm::Value::array();
  int passed_count = 0;
  for (const auto& c : CHECKS) {
    if (ok[c]) {
      axllm::Core::append(passed, c);
      ++passed_count;
    } else {
      axllm::Core::append(failed, axllm::object({{"check", c}, {"fix", remedy_for(c)}}));
    }
  }
  double score = std::round((static_cast<double>(passed_count) / CHECKS.size()) * 100.0) / 100.0;
  std::ostringstream logs;
  logs << passed_count << "/" << CHECKS.size() << " checks passed";
  return axllm::object({
      {"score", score},
      {"solved", passed_count == static_cast<int>(CHECKS.size())},
      {"passed", passed},
      {"failed", failed},
      {"logs", logs.str()},
  });
}

static axllm::Value fn_spec(const std::string& name, const std::string& description,
                           axllm::Value props, axllm::Value required = axllm::Value()) {
  axllm::Value parameters = axllm::object({{"type", "object"}, {"properties", props}});
  if (!required.is_null()) axllm::Core::set(parameters, "required", required);
  return axllm::object({{"name", name}, {"description", description}, {"parameters", parameters}});
}

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}})},
  }));

  // An independent verifier -- a separate ax() program, not the agent grading itself.
  auto verifier = axllm::ax("rubric:string, evidence:json -> passed:boolean, feedback:string, missing:string[]");
  verifier.set_instruction(
      "You are an independent rubric grader, not a self-critique. Pass only when the evidence clearly satisfies every part of the rubric.");

  // In-memory rule store. Verified, reusable rules go here -- not raw failure notes.
  std::map<std::string, std::string> memory_store;

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  runtime
      .register_callable("runExperiment", [](axllm::Value p) -> axllm::Value {
        return run_in_sandbox(axllm::display(axllm::Core::get(p, "plan", "")));
      })
      .register_callable("listChecks", [](axllm::Value) -> axllm::Value {
        axllm::Value out = axllm::Value::array();
        for (const auto& c : CHECKS) axllm::Core::append(out, c);
        return out;
      })
      .register_callable("grade", [&client, &verifier](axllm::Value p) -> axllm::Value {
        return verifier.forward(
            client,
            axllm::object({
                {"rubric", axllm::Core::get(p, "rubric", "")},
                {"evidence", axllm::Core::get(p, "evidence", axllm::Value::array())},
            }));
      })
      .register_callable("recall", [&memory_store](axllm::Value p) -> axllm::Value {
        std::string topic = to_lower(axllm::display(axllm::Core::get(p, "topic", "")));
        std::vector<std::string> words;
        std::istringstream ss(topic);
        std::string word;
        while (ss >> word) words.push_back(word);
        axllm::Value out = axllm::Value::array();
        for (const auto& entry : memory_store) {
          bool match = !topic.empty() && entry.first.find(topic) != std::string::npos;
          for (const auto& w : words) {
            if (!w.empty() && entry.first.find(w) != std::string::npos) match = true;
          }
          if (match) axllm::Core::append(out, entry.second);
        }
        return out;
      })
      .register_callable("remember", [&memory_store](axllm::Value p) -> axllm::Value {
        std::string rule = axllm::display(axllm::Core::get(p, "rule", ""));
        std::string evidence = axllm::display(axllm::Core::get(p, "evidence", ""));
        std::string key = to_lower(rule).substr(0, 48);
        memory_store[key] = rule + " :: " + evidence;
        return axllm::object({{"stored", true}, {"total", static_cast<double>(memory_store.size())}});
      });

  auto self_improving = axllm::agent(
      "goal:string, rubric:string -> answer:string, experiments:string[] \"Plans tried, in order\", learnedRules:string[]",
      axllm::object({
          {"contextFields", axllm::array({})},
          {"functions", axllm::array({
              fn_spec("runExperiment",
                      "Apply an ETL config plan; returns score, solved, passed[], failed[{check,fix}], logs. Pass an empty plan to discover the fixes.",
                      axllm::object({{"plan", axllm::object({{"type", "string"}})}}),
                      axllm::array({"plan"})),
              fn_spec("listChecks", "List the data-quality checks the experiment evaluates.", axllm::object({})),
              fn_spec("grade",
                      "Independent rubric grader. Pass only when the evidence meets the rubric.",
                      axllm::object({
                          {"rubric", axllm::object({{"type", "string"}})},
                          {"evidence", axllm::object({{"type", "array"}, {"items", axllm::object({{"type", "string"}})}})},
                      }),
                      axllm::array({"rubric", "evidence"})),
              fn_spec("recall", "Recall verified rules relevant to a topic.",
                      axllm::object({{"topic", axllm::object({{"type", "string"}})}}),
                      axllm::array({"topic"})),
              fn_spec("remember", "Store a verified, reusable rule (the rule, not raw notes).",
                      axllm::object({
                          {"rule", axllm::object({{"type", "string"}})},
                          {"evidence", axllm::object({{"type", "string"}})},
                      }),
                      axllm::array({"rule", "evidence"})),
          })},
          {"contextPolicy", axllm::object({{"preset", "adaptive"}, {"budget", "balanced"}})},
          {"executorOptions", axllm::object({
              {"description",
               std::string("Use the tools -- do not answer from your own knowledge.\n") +
                   "1. recall('etl data quality') to reuse anything already learned.\n" +
                   "2. runExperiment('') once to see every failing check and its fix.\n" +
                   "3. Build a plan applying all the fixes, then runExperiment again. Repeat until solved is true.\n" +
                   "4. grade the passing evidence against the rubric.\n" +
                   "5. For each check you fixed, remember(rule, evidence).\n" +
                   "6. Then return the answer, the plans you tried, and the learned rules."},
          })},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::Value result = self_improving.forward(
      client,
      axllm::object({
          {"goal", "Find an ETL config plan that cleans the dirty dataset so every data-quality check passes."},
          {"rubric", "All five checks (no-nulls, no-duplicates, numeric-types, trimmed-strings, outliers-handled) must pass, i.e. score 1.0."},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 18}}));

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

  // Persist the agent's verified rules so a future run's recall reuses them.
  axllm::Value learned = axllm::Core::get(result, "learnedRules", axllm::Value::array());
  for (const auto& rule : axllm::Core::iter(learned)) {
    std::string text = axllm::display(rule);
    memory_store[to_lower(text).substr(0, 48)] = text;
  }
  std::cout << "\nMemory now holds " << memory_store.size() << " rule(s) for next time.\n";
}

C++ Skills + Memory Ops Assistant

An on-call assistant that recalls past decisions from a memory store and loads the right runbook skill on demand, using the agent skills and memories subsystems.

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

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");
  // gpt-5.4 (not -mini): the recall/discover loop needs reasoning to proactively
  // pull memories + runbooks instead of stopping to ask for clarification.
  axllm::OpenAICompatibleClient client(axllm::object({
      {"api_key", key},
      {"model", model == nullptr || std::string(model).empty() ? "gpt-5.4" : model},
      {"model_config", axllm::object({{"temperature", 0}})},
  }));

  // ---------------------------------------------------------------------------
  // Memory store -- remembered decisions and postmortems. In production this is a
  // vector DB / BM25 index; here it is served to the actor's `recall([...])` via
  // the host memory-search results below. The actor pulls relevant entries into
  // scope through recall.
  // ---------------------------------------------------------------------------
  axllm::Value memories = axllm::array({
      axllm::object({
          {"id", "decision/db-failover"},
          {"content", "Decision (2026-02): during a primary DB failover, freeze writes via the feature flag `writes.enabled=false` BEFORE promoting the replica. Promoting first caused split-brain in inc-118."},
      }),
      axllm::object({
          {"id", "postmortem/inc-118"},
          {"content", "inc-118 root cause: replica promoted while primary still accepted writes. Mitigation: write-freeze flag + 90s replication-lag gate."},
      }),
      axllm::object({
          {"id", "decision/customer-comms"},
          {"content", "Decision: for Sev-1s affecting enterprise tenants, post a status-page update within 15 minutes and notify named TAMs directly."},
      }),
  });

  // ---------------------------------------------------------------------------
  // Skill store -- runbooks loaded into the executor prompt on demand via
  // `discover({ skills: [...] })`. Loaded skills persist across calls.
  // ---------------------------------------------------------------------------
  axllm::Value skills = axllm::array({
      axllm::object({
          {"id", "runbook-db-failover"},
          {"name", "DB failover runbook"},
          {"content", "## DB failover\n1. Set `writes.enabled=false`.\n2. Wait for replication lag < 5s.\n3. Promote replica.\n4. Re-point app via service discovery.\n5. Re-enable writes. 6. File postmortem within 48h."},
      }),
      axllm::object({
          {"id", "runbook-status-comms"},
          {"name", "Status communications runbook"},
          {"content", "## Status comms\n- Sev-1: status-page update within 15m, every 30m thereafter.\n- Enterprise impact: notify named TAMs directly.\n- Keep updates factual; no ETAs you cannot keep."},
      }),
  });

  // Token-based matching (a stand-in for BM25/vector): an entry matches if any word of any
  // search query (len >= 3) appears in it -- robust to phrase queries from the actor. These
  // native callbacks receive the actor's actual recall()/discover() queries.
  auto memories_search = [memories](axllm::Value searches, axllm::Value already_loaded) -> axllm::Value {
    axllm::Value out = axllm::array({});
    for (const auto& q : axllm::Core::iter(searches)) {
      for (const auto& w : axllm::Core::iter(axllm::Core::string_words(axllm::Core::string_lower(q)))) {
        if (!axllm::Core::truthy(axllm::Core::gte(axllm::Core::len(w), axllm::Value(3)))) continue;
        for (const auto& m : axllm::Core::iter(memories)) {
          if (axllm::Core::truthy(axllm::Core::contains(already_loaded, m))) continue;
          if (axllm::Core::truthy(axllm::Core::contains(out, m))) continue;
          axllm::Value id = axllm::Core::string_lower(axllm::Core::get(m, "id", axllm::Value("")));
          axllm::Value content = axllm::Core::string_lower(axllm::Core::get(m, "content", axllm::Value("")));
          if (axllm::Core::truthy(axllm::Core::contains(id, w)) || axllm::Core::truthy(axllm::Core::contains(content, w))) {
            axllm::Core::append(out, m);
          }
        }
      }
    }
    return out;
  };
  auto skills_search = [skills](axllm::Value searches) -> axllm::Value {
    axllm::Value out = axllm::array({});
    for (const auto& q : axllm::Core::iter(searches)) {
      for (const auto& w : axllm::Core::iter(axllm::Core::string_words(axllm::Core::string_lower(q)))) {
        if (!axllm::Core::truthy(axllm::Core::gte(axllm::Core::len(w), axllm::Value(3)))) continue;
        for (const auto& sk : axllm::Core::iter(skills)) {
          if (axllm::Core::truthy(axllm::Core::contains(out, sk))) continue;
          axllm::Value id = axllm::Core::string_lower(axllm::Core::get(sk, "id", axllm::Value("")));
          axllm::Value name = axllm::Core::string_lower(axllm::Core::get(sk, "name", axllm::Value("")));
          axllm::Value content = axllm::Core::string_lower(axllm::Core::get(sk, "content", axllm::Value("")));
          if (axllm::Core::truthy(axllm::Core::contains(id, w)) || axllm::Core::truthy(axllm::Core::contains(name, w)) || axllm::Core::truthy(axllm::Core::contains(content, w))) {
            axllm::Core::append(out, sk);
          }
        }
      }
    }
    return out;
  };

  auto assistant = axllm::agent(
      "situation:string -> guidance:string \"What to do, grounded in our decisions and runbooks\", steps:string[]",
      axllm::object({
          {"contextFields", axllm::array({})},
          // A base skill always loaded, independent of search.
          {"skills", axllm::array({
              axllm::object({
                  {"name", "house-style"},
                  {"content", "Be concise and operational. Prefer our remembered decisions over generic advice. Never invent flag names or steps -- cite the runbook."},
              }),
          })},
          // Native host search callbacks -- the actor's recall()/discover() reach these
          // (their presence auto-enables the memory + skill subsystems).
          {"onMemoriesSearch", axllm::register_memories_search(memories_search)},
          {"onSkillsSearch", axllm::register_skills_search(skills_search)},
          {"executorOptions", axllm::object({
              {"description",
               std::string("You do NOT know our internal flag names, incident history, or runbook steps from your own training.\n") +
                   "The only source of truth is our memory (past decisions/postmortems) and our runbook skills.\n" +
                   "1. recall the relevant past decisions and postmortems (e.g. the failover decision, inc-118).\n" +
                   "2. discover the matching runbook skill and read its exact steps and flag names.\n" +
                   "3. Answer with the precise ordered procedure, citing our exact flag names and runbook steps.\n" +
                   "Generic best-practice advice is WRONG here. Do NOT answer from general knowledge and do NOT ask for clarification -- recall and discover first."},
          })},
          {"runtime", axllm::object({{"language", "JavaScript"}})},
      }));

  axllm::runtime::quickjs::QuickJsCodeRuntime runtime;
  axllm::Value result = assistant.forward(
      client,
      axllm::object({
          {"situation",
           std::string("Our primary database is unhealthy and we're about to fail over -- the same class of ") +
               "incident as inc-118, and enterprise checkout is affected. Per our remembered decisions " +
               "and runbooks: what is the exact ordered procedure, and which specific feature flag must " +
               "we set before promoting the replica?"},
      }),
      axllm::object({{"runtime", axllm::Core::code_runtime_ref(runtime)}, {"max_actor_steps", 12}}));

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