use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use foundation_ai::agentic::tool_impl::{
ToolCallResult, ToolDefinition, ToolError, ToolImpl,
};
use foundation_ai::agentic::KvMemoryStore;
use foundation_ai::harness;
use foundation_ai::types::{
ArgType, Args, MessageRole, Messages, SessionId, TextContent, Tool, UserModelContent,
};
use foundation_compact::ids::new_scru128;
use foundation_core::valtron::valtron;
use foundation_db::{MemoryDocumentStore, MemoryStorage};
use foundation_jsonschema::scheme;
type Doc = MemoryDocumentStore;
type Mem = KvMemoryStore<MemoryStorage>;
struct GreetTool;
#[async_trait]
impl ToolImpl for GreetTool {
fn definition(&self) -> Tool {
Tool::SingleCommand(ToolDefinition {
name: "greet".into(),
category: "custom".into(),
description: "Greet someone by name.".into(),
arguments: Args::new(
scheme::object()
.required(
"name",
scheme::string().min_len(1).description("Name to greet"),
)
.build(),
),
returns: Some(Args::new(
scheme::object()
.required("greeting", scheme::string())
.build(),
)),
})
}
async fn execute(
&self,
arguments: HashMap<String, ArgType>,
) -> Result<ToolCallResult, ToolError> {
let name = match arguments.get("name") {
Some(ArgType::Text(s)) => s.clone(),
_ => {
return Err(ToolError::InvalidArguments {
tool: "greet".into(),
reason: "missing 'name'".into(),
})
}
};
Ok(ToolCallResult {
content: UserModelContent::Text(TextContent {
content: format!("Hello, {name}!"),
signature: None,
}),
error_detail: None,
})
}
}
#[valtron]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key =
std::env::var("ANTHROPIC_API_KEY").expect("ANTHROPIC_API_KEY must be set");
let builder = harness::claude_session::<Doc, Mem>(SessionId::new(), &api_key)?;
let agent = builder
.with_system_prompt(
"You are a helpful assistant with a custom greeting tool.",
)
.build()?;
agent.tool_manager().register(Arc::new(GreetTool));
let toolshed = agent.tool_manager().build_toolshed();
println!("ToolShed has {} tool(s):", toolshed.tools.len());
for tool in &toolshed.tools {
println!(" - {} ({})", tool.name(), tool.arg_summary());
}
let prompt = Messages::User {
id: new_scru128(),
role: MessageRole::User,
content: UserModelContent::Text(TextContent {
content: "Hello! Please use the greet tool to greet Alice.".into(),
signature: None,
}),
signature: None,
};
println!("\nAsking the agent about its tools...");
let records = agent.run_turn(prompt)?;
for record in &records {
println!("{record:?}");
}
println!("\nAgent responded! Got {} records.", records.len());
agent.end()?;
Ok(())
}