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.
- Provider:
google-gemini - Env:
GOOGLE_APIKEY - Level:
advanced - Run:
npm run example -- cpp src/examples/cpp/long-agents/incident_log_forensics.cpp - Source: src/examples/cpp/long-agents/incident_log_forensics.cpp
#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.
- Provider:
google-gemini - Env:
GOOGLE_APIKEY - Level:
advanced - Run:
npm run example -- cpp src/examples/cpp/long-agents/codebase_peek_map.cpp - Source: src/examples/cpp/long-agents/codebase_peek_map.cpp
#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.
- Provider:
google-gemini - Env:
GOOGLE_APIKEY - Level:
advanced - Run:
npm run example -- cpp src/examples/cpp/long-agents/data_analyst_with_tools.cpp - Source: src/examples/cpp/long-agents/data_analyst_with_tools.cpp
#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.
- Provider:
openai - Env:
OPENAI_API_KEY,OPENAI_APIKEY - Level:
advanced - Run:
npm run example -- cpp src/examples/cpp/long-agents/self_improving_lab.cpp - Source: src/examples/cpp/long-agents/self_improving_lab.cpp
#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.
- Provider:
openai - Env:
OPENAI_API_KEY,OPENAI_APIKEY - Level:
advanced - Run:
npm run example -- cpp src/examples/cpp/long-agents/skills_and_memory_assistant.cpp - Source: src/examples/cpp/long-agents/skills_and_memory_assistant.cpp
#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";
}