use axllm::{agent_with_options, AxAIClient, AxResult};
use serde_json::{json, Value};
use std::cell::RefCell;
use std::rc::Rc;
struct ScriptedClient;
impl AxAIClient for ScriptedClient {
fn chat(&mut self, _request: Value) -> AxResult<Value> {
let content = json!({
"answer": "Ax composes typed LLM programs.",
"reasoning": "The playbook lacked a brevity rule.",
"errorIdentification": "Answer was too verbose.",
"rootCauseAnalysis": "No guidance on conciseness.",
"correctApproach": "Add a concise-answer guideline.",
"keyInsight": "Prefer one-sentence answers.",
"bulletTags": [],
"operations": [
{"type": "ADD", "section": "Guidelines", "content": "Answer in one concise sentence."}
]
})
.to_string();
Ok(json!({"results": [{"content": content}]}))
}
}
fn main() -> AxResult<()> {
let mut agent = agent_with_options(
"question:string -> answer:string",
json!({"name": "qa", "description": "Answer the question."}),
)?;
let student = Rc::new(RefCell::new(ScriptedClient));
let mut pb = agent.playbook(
student,
None::<Rc<RefCell<ScriptedClient>>>,
json!({"target": "responder", "maxEpochs": 1}),
)?;
let mut metric = |args: &Value| -> Value {
let answer = args
.get("prediction")
.and_then(|p| p.get("answer"))
.and_then(Value::as_str)
.unwrap_or("");
if answer.is_empty() {
json!(0.0)
} else {
json!(1.0)
}
};
let examples = vec![
json!({"question": "What is Ax?", "contextData": {}}),
json!({"question": "Why typed signatures?", "contextData": {}}),
];
let result = pb.evolve(&examples, &mut metric, &json!({}))?;
let rendered = pb.render();
let state = pb.to_json();
assert!(
result.get("bestScore").is_some(),
"missing bestScore: {result}"
);
assert!(state.get("playbook").is_some(), "missing playbook: {state}");
println!("rendered: {rendered}");
println!("rust-agent-playbook-ok");
Ok(())
}