#![allow(clippy::expect_used, clippy::pedantic)]
use std::sync::Arc;
use loopctl::Tool;
use loopctl::config::SessionConfig;
use loopctl::engine::core::Loop;
use loopctl::engine::{BareLoop, RunConfig};
use loopctl::testing::MockApiClient;
use loopctl::tool::ToolRegistry;
use serde::Deserialize;
#[derive(Tool, Deserialize)]
#[tool(name = "echo", description = "Echo back the provided message")]
struct EchoInput {
message: String,
}
impl EchoInput {
async fn run(
&self,
input: EchoInput,
_ctx: &loopctl::tool::ToolContext,
) -> Result<loopctl::tool::ToolOutput, loopctl::tool::ToolError> {
Ok(loopctl::tool::ToolOutput::text(input.message))
}
}
#[tokio::main]
async fn main() {
let client = MockApiClient::new("echo-model").with_responses(vec![
loopctl::testing::MockResponse {
text: "one go".to_string(),
tool_call: Some(loopctl::testing::MockToolCall {
id: "call_1".to_string(),
name: "echo".to_string(),
input: serde_json::json!({"message": "derived!"}),
}),
stop_reason: "tool_use".to_string(),
},
loopctl::testing::MockResponse {
text: "all done".to_string(),
tool_call: None,
stop_reason: "end_turn".to_string(),
},
]);
let mut registry = ToolRegistry::new();
registry.register(EchoInput {
message: String::new(),
});
let mut agent = BareLoop::new(Arc::new(client), registry, SessionConfig::default());
let outcome = agent.run("say it", &RunConfig::default()).await;
println!("{outcome:?}");
}